Ensure that the authenticated users can't access each other's directories and files by providing relative paths. #5734

This commit is contained in:
Aditya Toshniwal 2023-01-13 12:29:21 +05:30 committed by GitHub
parent 83b207e7da
commit 8b236e7bc8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 77 additions and 126 deletions

View File

@ -19,8 +19,9 @@ from flask_babel import gettext as _
from flask_security import login_required, current_user
from pgadmin.misc.bgprocess.processes import BatchProcess, IProcessDesc
from pgadmin.utils import PgAdminModule, get_storage_directory, html, \
fs_short_path, document_dir, does_utility_exist, get_server
from pgadmin.utils.ajax import make_json_response, bad_request
fs_short_path, document_dir, does_utility_exist, get_server, \
filename_with_file_manager_path
from pgadmin.utils.ajax import make_json_response, bad_request, unauthorized
from config import PG_DEFAULT_DRIVER
from pgadmin.model import Server, SharedServer
@ -189,40 +190,6 @@ def script():
)
def filename_with_file_manager_path(_file, create_file=True):
"""
Args:
file: File name returned from client file manager
create_file: Set flag to False when file creation doesn't required
Returns:
Filename to use for backup with full path taken from preference
"""
# Set file manager directory from preference
storage_dir = get_storage_directory()
if storage_dir:
_file = os.path.join(storage_dir, _file.lstrip('/').lstrip('\\'))
elif not os.path.isabs(_file):
_file = os.path.join(document_dir(), _file)
def short_filepath():
short_path = fs_short_path(_file)
# fs_short_path() function may return empty path on Windows
# if directory doesn't exists. In that case we strip the last path
# component and get the short path.
if os.name == 'nt' and short_path == '':
base_name = os.path.basename(_file)
dir_name = os.path.dirname(_file)
short_path = fs_short_path(dir_name) + '\\' + base_name
return short_path
if create_file:
# Touch the file to get the short path of the file on windows.
with open(_file, 'a'):
return short_filepath()
return short_filepath()
def _get_args_params_values(data, conn, backup_obj_type, backup_file, server,
manager):
"""
@ -367,6 +334,8 @@ def create_backup_objects_job(sid):
try:
backup_file = filename_with_file_manager_path(
data['file'], (data.get('format', '') != 'directory'))
except PermissionError as e:
return unauthorized(errormsg=str(e))
except Exception as e:
return bad_request(errormsg=str(e))

View File

@ -17,8 +17,9 @@ from flask_babel import gettext as _
from flask_security import login_required, current_user
from pgadmin.misc.bgprocess.processes import BatchProcess, IProcessDesc
from pgadmin.utils import PgAdminModule, get_storage_directory, html, \
fs_short_path, document_dir, IS_WIN, does_utility_exist
from pgadmin.utils.ajax import make_json_response, bad_request
fs_short_path, document_dir, IS_WIN, does_utility_exist, \
filename_with_file_manager_path
from pgadmin.utils.ajax import make_json_response, bad_request, unauthorized
from config import PG_DEFAULT_DRIVER
from pgadmin.model import Server
@ -145,33 +146,6 @@ def script():
)
def filename_with_file_manager_path(_file, _present=False):
"""
Args:
file: File name returned from client file manager
Returns:
Filename to use for backup with full path taken from preference
"""
# Set file manager directory from preference
storage_dir = get_storage_directory()
if storage_dir:
_file = os.path.join(storage_dir, _file.lstrip('/').lstrip('\\'))
elif not os.path.isabs(_file):
_file = os.path.join(document_dir(), _file)
if not _present:
# Touch the file to get the short path of the file on windows.
with open(_file, 'a'):
return fs_short_path(_file)
else:
if not os.path.isfile(_file):
return None
return fs_short_path(_file)
def _get_ignored_column_list(data, driver, conn):
"""
Get list of ignored columns for import/export.
@ -297,7 +271,9 @@ def create_import_export_job(sid):
if 'filename' in data:
try:
_file = filename_with_file_manager_path(
data['filename'], data['is_import'])
data['filename'], not data['is_import'])
except PermissionError as e:
return unauthorized(errormsg=str(e))
except Exception as e:
return bad_request(errormsg=str(e))

View File

@ -20,10 +20,11 @@ from flask_security import login_required, current_user
from pgadmin.utils import PgAdminModule
from pgadmin.utils.ajax import bad_request
from pgadmin.utils.constants import MIMETYPE_APP_JS
from pgadmin.utils.ajax import make_json_response, internal_server_error
from pgadmin.utils.ajax import make_json_response, internal_server_error, \
unauthorized
from pgadmin.model import ServerGroup, Server
from pgadmin.utils import clear_database_servers, dump_database_servers,\
load_database_servers, validate_json_data
load_database_servers, validate_json_data, filename_with_file_manager_path
from urllib.parse import unquote
from pgadmin.utils.paths import get_storage_directory
@ -118,6 +119,14 @@ def load_servers():
# retrieve storage directory path
storage_manager_path = get_storage_directory()
try:
file_path = filename_with_file_manager_path(file_path)
except PermissionError as e:
return unauthorized(errormsg=str(e))
except Exception as e:
return bad_request(errormsg=str(e))
if storage_manager_path:
# generate full path of file
file_path = os.path.join(

View File

@ -18,8 +18,10 @@ from flask_babel import gettext as _
from flask_security import login_required, current_user
from pgadmin.misc.bgprocess.processes import BatchProcess, IProcessDesc
from pgadmin.utils import PgAdminModule, get_storage_directory, html, \
fs_short_path, document_dir, does_utility_exist, get_server
from pgadmin.utils.ajax import make_json_response, bad_request
fs_short_path, document_dir, does_utility_exist, get_server, \
filename_with_file_manager_path
from pgadmin.utils.ajax import make_json_response, bad_request, \
internal_server_error
from config import PG_DEFAULT_DRIVER
from pgadmin.model import Server, SharedServer
@ -129,28 +131,6 @@ def script():
)
def filename_with_file_manager_path(_file):
"""
Args:
file: File name returned from client file manager
Returns:
Filename to use for backup with full path taken from preference
"""
# Set file manager directory from preference
storage_dir = get_storage_directory()
if storage_dir:
_file = os.path.join(storage_dir, _file.lstrip('/').lstrip('\\'))
elif not os.path.isabs(_file):
_file = os.path.join(document_dir(), _file)
if not os.path.isfile(_file) and not os.path.exists(_file):
return None
return fs_short_path(_file)
def _get_create_req_data():
"""
Get data from request for create restore job.
@ -164,7 +144,7 @@ def _get_create_req_data():
try:
_file = filename_with_file_manager_path(data['file'])
except Exception as e:
return True, bad_request(errormsg=str(e)), data
return True, internal_server_error(errormsg=str(e)), data, None
if _file is None:
return True, make_json_response(

View File

@ -260,6 +260,45 @@ def get_complete_file_path(file, validate=True):
return file
def filename_with_file_manager_path(_file, create_file=False,
skip_permission_check=False):
"""
Args:
file: File name returned from client file manager
create_file: Set flag to False when file creation doesn't required
Returns:
Filename to use for backup with full path taken from preference
"""
# Set file manager directory from preference
storage_dir = get_storage_directory()
from pgadmin.misc.file_manager import Filemanager
Filemanager.check_access_permission(
storage_dir, _file, skip_permission_check)
if storage_dir:
_file = os.path.join(storage_dir, _file.lstrip('/').lstrip('\\'))
elif not os.path.isabs(_file):
_file = os.path.join(document_dir(), _file)
def short_filepath():
short_path = fs_short_path(_file)
# fs_short_path() function may return empty path on Windows
# if directory doesn't exists. In that case we strip the last path
# component and get the short path.
if os.name == 'nt' and short_path == '':
base_name = os.path.basename(_file)
dir_name = os.path.dirname(_file)
short_path = fs_short_path(dir_name) + '\\' + base_name
return short_path
if create_file:
# Touch the file to get the short path of the file on windows.
with open(_file, 'a'):
return short_filepath()
return short_filepath()
def does_utility_exist(file):
"""
This function will check the utility file exists on given path.
@ -434,27 +473,12 @@ def dump_database_servers(output_file, selected_servers,
object_dict["Servers"] = server_dict
# retrieve storage directory path
storage_manager_path = None
if not from_setup:
storage_manager_path = get_storage_directory(user)
# generate full path of file
file_path = unquote(output_file)
from pgadmin.misc.file_manager import Filemanager
try:
Filemanager.check_access_permission(storage_manager_path, file_path,
from_setup)
file_path = filename_with_file_manager_path(
unquote(output_file), skip_permission_check=from_setup)
except Exception as e:
return _handle_error(str(e), from_setup)
if storage_manager_path is not None:
file_path = os.path.join(
storage_manager_path,
file_path.lstrip('/').lstrip('\\')
)
# write to file
file_content = json.dumps(object_dict, indent=4)
error_str = "Error: {0}"
@ -548,19 +572,12 @@ def load_database_servers(input_file, selected_servers,
if user is None:
return False, USER_NOT_FOUND % load_user
# retrieve storage directory path
storage_manager_path = None
if not from_setup:
storage_manager_path = get_storage_directory(user)
# generate full path of file
file_path = unquote(input_file)
if storage_manager_path:
# generate full path of file
file_path = os.path.join(
storage_manager_path,
file_path.lstrip('/').lstrip('\\')
)
try:
file_path = filename_with_file_manager_path(
unquote(input_file), skip_permission_check=from_setup)
except Exception as e:
return _handle_error(str(e), from_setup)
try:
with open(file_path) as f:

View File

@ -8517,9 +8517,9 @@ react-checkbox-tree@^1.7.2:
nanoid "^3.0.0"
prop-types "^15.5.8"
"react-data-grid@git+https://github.com/EnterpriseDB/react-data-grid.git/#200d2f5e02de694e3e9ffbe177c279bc40240fb8":
"react-data-grid@git+https://github.com/pgadmin-org/react-data-grid.git/#200d2f5e02de694e3e9ffbe177c279bc40240fb8":
version "7.0.0-beta.14"
resolved "git+https://github.com/EnterpriseDB/react-data-grid.git/#200d2f5e02de694e3e9ffbe177c279bc40240fb8"
resolved "git+https://github.com/pgadmin-org/react-data-grid.git/#200d2f5e02de694e3e9ffbe177c279bc40240fb8"
dependencies:
clsx "^1.1.1"
@ -10337,9 +10337,9 @@ watchpack@^2.4.0:
glob-to-regexp "^0.4.1"
graceful-fs "^4.1.2"
"webcabin-docker@git+https://github.com/EnterpriseDB/wcDocker/#3df8aac825ee2892f4d824de273b779cc6dbcad8":
"webcabin-docker@git+https://github.com/pgadmin-org/wcdocker/#3df8aac825ee2892f4d824de273b779cc6dbcad8":
version "2.2.5"
resolved "git+https://github.com/EnterpriseDB/wcDocker/#3df8aac825ee2892f4d824de273b779cc6dbcad8"
resolved "git+https://github.com/pgadmin-org/wcdocker/#3df8aac825ee2892f4d824de273b779cc6dbcad8"
dependencies:
"@fortawesome/fontawesome-free" "^5.14.0"
FileSaver "^0.10.0"