* autoload.cc (PrivilegeCheck): Define.
* fhandler.cc (fhandler_base::open): Always try opening with backup resp. restore intent. * fhandler_disk_file.cc (fhandler_disk_file::opendir): Always try opening with backup intent. (fhandler_disk_file::readdir): Ditto when trying to retrieve file id explicitely. * security.cc (check_file_access): Replace pbuf with correctly PPRIVILEGE_SET typed pset. Check explicitely for backup and/or restore privileges when AccessCheck fails, to circumvent AccessCheck shortcoming. Add comment to explain.
This commit is contained in:
parent
7af26e0cc0
commit
2c1ffdbf5e
|
@ -1,3 +1,17 @@
|
||||||
|
2006-10-13 Corinn6 Vinschen <corinna@vinschen.de>
|
||||||
|
|
||||||
|
* autoload.cc (PrivilegeCheck): Define.
|
||||||
|
* fhandler.cc (fhandler_base::open): Always try opening with backup
|
||||||
|
resp. restore intent.
|
||||||
|
* fhandler_disk_file.cc (fhandler_disk_file::opendir): Always try
|
||||||
|
opening with backup intent.
|
||||||
|
(fhandler_disk_file::readdir): Ditto when trying to retrieve file id
|
||||||
|
explicitely.
|
||||||
|
* security.cc (check_file_access): Replace pbuf with correctly
|
||||||
|
PPRIVILEGE_SET typed pset. Check explicitely for backup and/or restore
|
||||||
|
privileges when AccessCheck fails, to circumvent AccessCheck
|
||||||
|
shortcoming. Add comment to explain.
|
||||||
|
|
||||||
2006-10-13 Christopher Faylor <cgf@timesys.com>
|
2006-10-13 Christopher Faylor <cgf@timesys.com>
|
||||||
|
|
||||||
* winsup.h: Turn off DEBUGGING.
|
* winsup.h: Turn off DEBUGGING.
|
||||||
|
|
|
@ -347,6 +347,7 @@ LoadDLLfunc (LsaQueryInformationPolicy, 12, advapi32)
|
||||||
LoadDLLfunc (MakeSelfRelativeSD, 12, advapi32)
|
LoadDLLfunc (MakeSelfRelativeSD, 12, advapi32)
|
||||||
LoadDLLfunc (OpenProcessToken, 12, advapi32)
|
LoadDLLfunc (OpenProcessToken, 12, advapi32)
|
||||||
LoadDLLfunc (OpenThreadToken, 16, advapi32)
|
LoadDLLfunc (OpenThreadToken, 16, advapi32)
|
||||||
|
LoadDLLfunc (PrivilegeCheck, 12, advapi32)
|
||||||
// LoadDLLfunc (RegCloseKey, 4, advapi32)
|
// LoadDLLfunc (RegCloseKey, 4, advapi32)
|
||||||
LoadDLLfunc (RegCreateKeyExA, 36, advapi32)
|
LoadDLLfunc (RegCreateKeyExA, 36, advapi32)
|
||||||
LoadDLLfunc (RegDeleteKeyA, 8, advapi32)
|
LoadDLLfunc (RegDeleteKeyA, 8, advapi32)
|
||||||
|
|
|
@ -620,13 +620,22 @@ fhandler_base::open (int flags, mode_t mode)
|
||||||
create_options = FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_FOR_RECOVERY;
|
create_options = FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_FOR_RECOVERY;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
create_options = 0;
|
|
||||||
if ((flags & O_ACCMODE) == O_RDONLY)
|
if ((flags & O_ACCMODE) == O_RDONLY)
|
||||||
|
{
|
||||||
access = GENERIC_READ;
|
access = GENERIC_READ;
|
||||||
|
create_options = FILE_OPEN_FOR_BACKUP_INTENT;
|
||||||
|
}
|
||||||
else if ((flags & O_ACCMODE) == O_WRONLY)
|
else if ((flags & O_ACCMODE) == O_WRONLY)
|
||||||
|
{
|
||||||
access = GENERIC_WRITE | FILE_READ_ATTRIBUTES;
|
access = GENERIC_WRITE | FILE_READ_ATTRIBUTES;
|
||||||
|
create_options = FILE_OPEN_FOR_RECOVERY;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
access = GENERIC_READ | GENERIC_WRITE;
|
access = GENERIC_READ | GENERIC_WRITE;
|
||||||
|
create_options = FILE_OPEN_FOR_BACKUP_INTENT
|
||||||
|
| FILE_OPEN_FOR_RECOVERY;
|
||||||
|
}
|
||||||
if (flags & O_SYNC)
|
if (flags & O_SYNC)
|
||||||
create_options |= FILE_WRITE_THROUGH;
|
create_options |= FILE_WRITE_THROUGH;
|
||||||
if (flags & O_DIRECT)
|
if (flags & O_DIRECT)
|
||||||
|
|
|
@ -1606,6 +1606,7 @@ fhandler_disk_file::opendir ()
|
||||||
SYNCHRONIZE | FILE_LIST_DIRECTORY,
|
SYNCHRONIZE | FILE_LIST_DIRECTORY,
|
||||||
&attr, &io, wincap.shared (),
|
&attr, &io, wincap.shared (),
|
||||||
FILE_SYNCHRONOUS_IO_NONALERT
|
FILE_SYNCHRONOUS_IO_NONALERT
|
||||||
|
| FILE_OPEN_FOR_BACKUP_INTENT
|
||||||
| FILE_DIRECTORY_FILE);
|
| FILE_DIRECTORY_FILE);
|
||||||
if (!NT_SUCCESS (status))
|
if (!NT_SUCCESS (status))
|
||||||
{
|
{
|
||||||
|
@ -1869,7 +1870,7 @@ go_ahead:
|
||||||
InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE,
|
InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE,
|
||||||
dir->__handle , NULL);
|
dir->__handle , NULL);
|
||||||
if (!NtOpenFile (&hdl, READ_CONTROL, &attr, &io,
|
if (!NtOpenFile (&hdl, READ_CONTROL, &attr, &io,
|
||||||
wincap.shared (), 0))
|
wincap.shared (), FILE_OPEN_FOR_BACKUP_INTENT))
|
||||||
{
|
{
|
||||||
de->d_ino = readdir_get_ino_by_handle (hdl);
|
de->d_ino = readdir_get_ino_by_handle (hdl);
|
||||||
CloseHandle (hdl);
|
CloseHandle (hdl);
|
||||||
|
|
|
@ -1953,8 +1953,9 @@ check_file_access (const char *fn, int flags)
|
||||||
|
|
||||||
HANDLE hToken;
|
HANDLE hToken;
|
||||||
BOOL status;
|
BOOL status;
|
||||||
char pbuf[sizeof (PRIVILEGE_SET) + 3 * sizeof (LUID_AND_ATTRIBUTES)];
|
DWORD desired = 0, granted;
|
||||||
DWORD desired = 0, granted, plength = sizeof pbuf;
|
DWORD plength = sizeof (PRIVILEGE_SET) + 3 * sizeof (LUID_AND_ATTRIBUTES);
|
||||||
|
PPRIVILEGE_SET pset = (PPRIVILEGE_SET) alloca (plength);
|
||||||
static GENERIC_MAPPING NO_COPY mapping = { FILE_GENERIC_READ,
|
static GENERIC_MAPPING NO_COPY mapping = { FILE_GENERIC_READ,
|
||||||
FILE_GENERIC_WRITE,
|
FILE_GENERIC_WRITE,
|
||||||
FILE_GENERIC_EXECUTE,
|
FILE_GENERIC_EXECUTE,
|
||||||
|
@ -1974,10 +1975,46 @@ check_file_access (const char *fn, int flags)
|
||||||
if (flags & X_OK)
|
if (flags & X_OK)
|
||||||
desired |= FILE_EXECUTE;
|
desired |= FILE_EXECUTE;
|
||||||
if (!AccessCheck (sd, hToken, desired, &mapping,
|
if (!AccessCheck (sd, hToken, desired, &mapping,
|
||||||
(PPRIVILEGE_SET) pbuf, &plength, &granted, &status))
|
pset, &plength, &granted, &status))
|
||||||
__seterrno ();
|
__seterrno ();
|
||||||
else if (!status)
|
else if (!status)
|
||||||
|
{
|
||||||
|
/* CV, 2006-10-16: Now, that's really weird. Imagine a user who has no
|
||||||
|
standard access to a file, but who has backup and restore privileges
|
||||||
|
and these privileges are enabled in the access token. One would
|
||||||
|
expect that the AccessCheck function takes this into consideration
|
||||||
|
when returning the access status. Otherwise, why bother with the
|
||||||
|
pset parameter, right?
|
||||||
|
But not so. AccessCheck actually returns a status of "false" here,
|
||||||
|
even though opening a file with backup resp. restore intent
|
||||||
|
naturally succeeds for this user. This definitely spoils the results
|
||||||
|
of access(2) for administrative users or the SYSTEM account. So, in
|
||||||
|
case the access check fails, another check against the user's
|
||||||
|
backup/restore privileges has to be made. Sigh. */
|
||||||
|
int granted_flags = 0;
|
||||||
|
if (flags & R_OK)
|
||||||
|
{
|
||||||
|
pset->PrivilegeCount = 1;
|
||||||
|
pset->Control = 0;
|
||||||
|
pset->Privilege[0].Luid = *privilege_luid (SE_BACKUP_PRIV);
|
||||||
|
pset->Privilege[0].Attributes = 0;
|
||||||
|
if (PrivilegeCheck (hToken, pset, &status) && status)
|
||||||
|
granted_flags |= R_OK;
|
||||||
|
}
|
||||||
|
if (flags & W_OK)
|
||||||
|
{
|
||||||
|
pset->PrivilegeCount = 1;
|
||||||
|
pset->Control = 0;
|
||||||
|
pset->Privilege[0].Luid = *privilege_luid (SE_RESTORE_PRIV);
|
||||||
|
pset->Privilege[0].Attributes = 0;
|
||||||
|
if (PrivilegeCheck (hToken, pset, &status) && status)
|
||||||
|
granted_flags |= W_OK;
|
||||||
|
}
|
||||||
|
if (granted_flags == flags)
|
||||||
|
ret = 0;
|
||||||
|
else
|
||||||
set_errno (EACCES);
|
set_errno (EACCES);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
ret = 0;
|
ret = 0;
|
||||||
done:
|
done:
|
||||||
|
|
Loading…
Reference in New Issue