+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>
* winsup.h: Turn off DEBUGGING.
LoadDLLfunc (MakeSelfRelativeSD, 12, advapi32)
LoadDLLfunc (OpenProcessToken, 12, advapi32)
LoadDLLfunc (OpenThreadToken, 16, advapi32)
+LoadDLLfunc (PrivilegeCheck, 12, advapi32)
// LoadDLLfunc (RegCloseKey, 4, advapi32)
LoadDLLfunc (RegCreateKeyExA, 36, advapi32)
LoadDLLfunc (RegDeleteKeyA, 8, advapi32)
create_options = FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_FOR_RECOVERY;
break;
default:
- create_options = 0;
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)
- access = GENERIC_WRITE | FILE_READ_ATTRIBUTES;
+ {
+ access = GENERIC_WRITE | FILE_READ_ATTRIBUTES;
+ create_options = FILE_OPEN_FOR_RECOVERY;
+ }
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)
create_options |= FILE_WRITE_THROUGH;
if (flags & O_DIRECT)
SYNCHRONIZE | FILE_LIST_DIRECTORY,
&attr, &io, wincap.shared (),
FILE_SYNCHRONOUS_IO_NONALERT
+ | FILE_OPEN_FOR_BACKUP_INTENT
| FILE_DIRECTORY_FILE);
if (!NT_SUCCESS (status))
{
InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE,
dir->__handle , NULL);
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);
CloseHandle (hdl);
HANDLE hToken;
BOOL status;
- char pbuf[sizeof (PRIVILEGE_SET) + 3 * sizeof (LUID_AND_ATTRIBUTES)];
- DWORD desired = 0, granted, plength = sizeof pbuf;
+ DWORD desired = 0, granted;
+ 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,
FILE_GENERIC_WRITE,
FILE_GENERIC_EXECUTE,
if (flags & X_OK)
desired |= FILE_EXECUTE;
if (!AccessCheck (sd, hToken, desired, &mapping,
- (PPRIVILEGE_SET) pbuf, &plength, &granted, &status))
+ pset, &plength, &granted, &status))
__seterrno ();
else if (!status)
- set_errno (EACCES);
+ {
+ /* 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);
+ }
else
ret = 0;
done: