Re: Как скопиpовать пеpмиссии на файл?
- From
- Alex Fedotov ()
- To
- Serge Mikhaylov
- Date
- 2002-02-24T11:58:50Z
- Area
- SU.WINDOWS.NT.PROG
From: "Alex Fedotov" <me@alexfedotov.com>
Serge Mikhaylov wrote:
> Киньте плиз пpимеpчиком. Мне не нужно pазбиpать эту таблицу, нужно только
> пpочитать ее и записать. МОжно и пpо овнеpшип тоже =) Спасибо.
В приложении в конце функция CopyFileSecurity, которая копирует указанные
части дескриптора безопасности одного файла на другой. Использоваться эта
функция может, например, таким образом:
CopyFileSecurity(_T("C:\\config.sys"), _T("C:\\autoexec.bat"),
DACL_SECURITY_INFORMATION); // копирует DACL
CopyFileSecurity(_T("C:\\config.sys"), _T("C:\\autoexec.bat"),
OWNER_SECURITY_INFORMATION); // копирует владельца
Можно указать и несколько флагов одновременно.
Для успешной работы функции нужны некоторые привилегии или права доступа к
файлам (что вполне естественно, в противном случае все бы копировали
разрешения направо и налево), а именно:
1) Чтобы скопировать владельца, нужно:
a) иметь привилегию SeBackupPrivilege либо право доступа READ_CONTROL к
исходному файлу, и
б) иметь привилегию SeRestorePrivilege (в некоторых случаях достаточно
права доступа WRITE_OWNER к выходному файлу).
2) Чтобы скопировать разрешения (DACL), нужно:
a) иметь привилегию SeBackupPrivilege либо право доступа READ_CONTROL к
исходному файлу, и
б) иметь привилегию SeRestorePrivilege либо право доступа WRITE_DAC к
выходному файлу.
3) Чтобы скопировать аудит, нужно:
a) иметь привилегию SeSecurityPrivilege, и
б) иметь привилегию SeBackupPrivilege либо право доступа READ_CONTROL к
исходному файлу, и
в) иметь привилегию SeRestorePrivilege либо право доступа READ_CONTROL к
выходному файлу.
С практической точки зрения это означает, что администраторы могут
использовать эту функцию без ограничений, так называемые "backup operators"
могут копировать все, кроме SACL, а остальные пользователи могут копировать
только DACL, и то, если позволяют права доступа к конкретным файлам (имеется
в виду стандартное распределение привилегий сразу после установки NT).
Я проверял этот код на XP. Потестируй на остальных версиях, если не будет
проблем, я тогда себе на сайт его в качестве примера выложу.
Стоит также заметить, что существует также альтернативный способ решения
проблемы: с помощью функций BackupRead и BackupWrite можно скопировать поток
дескриптора безопасности из одного файла в другой. Исследованием этого
метода пусть займется кто-нибудь другой, а я лучше пойду что-нибудь полезное
сделаю.
-- Alex Fedotov
Приложение. Исходный код CopyFileSecurity.
// extended version of GetFileSecurity
DWORD ExGetFileSecurity(
IN PCTSTR pszFileName,
IN ULONG SecurityInformation,
IN BOOL bBackupPrivilege,
OUT PSECURITY_DESCRIPTOR * ppSecDesc
)
{
_ASSERTE(pszFileName != NULL);
_ASSERTE(ppSecDesc != NULL);
*ppSecDesc = NULL;
DWORD dwAccess = READ_CONTROL;
if (SecurityInformation & SACL_SECURITY_INFORMATION)
dwAccess |= ACCESS_SYSTEM_SECURITY;
DWORD dwFlags = FILE_ATTRIBUTE_NORMAL;
if (bBackupPrivilege)
dwFlags |= FILE_FLAG_BACKUP_SEMANTICS;
// open file; use backup semantics if SeBackupPrivilege is available
HANDLE hFile = CreateFile(pszFileName, dwAccess,
FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, dwFlags, NULL);
if (hFile == INVALID_HANDLE_VALUE)
return GetLastError();
PSECURITY_DESCRIPTOR pSecDesc;
DWORD cbNeeded;
DWORD dwError;
// determine size of the security descriptor
if (!GetKernelObjectSecurity(hFile, SecurityInformation,
NULL, 0, &cbNeeded))
{
dwError = GetLastError();
if (dwError != ERROR_INSUFFICIENT_BUFFER)
{
CloseHandle(hFile);
return dwError;
}
}
// allocate memory for the security descriptor
pSecDesc = (PSECURITY_DESCRIPTOR)LocalAlloc(LMEM_FIXED, cbNeeded);
if (pSecDesc == NULL)
{
CloseHandle(hFile);
return ERROR_NOT_ENOUGH_MEMORY;
}
// retrieve security descriptor
if (!GetKernelObjectSecurity(hFile, SecurityInformation, pSecDesc,
cbNeeded, &cbNeeded))
{
dwError = GetLastError();
LocalFree((HLOCAL)pSecDesc);
}
else
{
dwError = ERROR_SUCCESS;
*ppSecDesc = pSecDesc;
}
CloseHandle(hFile);
return dwError;
}
// extended version of SetFileSecurity
DWORD ExSetFileSecurity(
IN PCTSTR pszFileName,
IN ULONG SecurityInformation,
IN BOOL bRestorePrivilege,
IN PSECURITY_DESCRIPTOR pSecDesc
)
{
_ASSERTE(pszFileName != NULL);
_ASSERTE(pSecDesc != NULL);
DWORD dwAccess = 0;
if (SecurityInformation & OWNER_SECURITY_INFORMATION)
dwAccess |= WRITE_OWNER;
if (SecurityInformation & GROUP_SECURITY_INFORMATION)
dwAccess |= WRITE_OWNER;
if (SecurityInformation & DACL_SECURITY_INFORMATION)
dwAccess |= WRITE_DAC;
if (SecurityInformation & SACL_SECURITY_INFORMATION)
dwAccess |= ACCESS_SYSTEM_SECURITY;
DWORD dwFlags = FILE_ATTRIBUTE_NORMAL;
if (bRestorePrivilege)
dwFlags |= FILE_FLAG_BACKUP_SEMANTICS;
// open file; use backup semantics if SeRestorePrivilege is available
HANDLE hFile = CreateFile(pszFileName, dwAccess,
FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, dwFlags, NULL);
if (hFile == INVALID_HANDLE_VALUE)
return GetLastError();
DWORD dwError = ERROR_SUCCESS;
// assign file security
if (!SetKernelObjectSecurity(hFile, SecurityInformation, pSecDesc))
dwError = GetLastError();
CloseHandle(hFile);
return dwError;
}
// enables or disables a privilege
BOOL EnablePrivilege(
IN PCTSTR pszPrivilegeName,
IN BOOL bEnable,
IN PBOOL pbPreviousState
)
{
_ASSERTE(pszPrivilegeName != NULL);
TOKEN_PRIVILEGES Priv, PrivOld;
DWORD cbPriv = sizeof(PrivOld);
HANDLE hToken = NULL;
if (pbPreviousState != NULL)
*pbPreviousState = FALSE;
// obtain token of the current thread
if (!OpenThreadToken(GetCurrentThread(),
TOKEN_QUERY|TOKEN_ADJUST_PRIVILEGES,
FALSE, &hToken))
{
if (GetLastError() != ERROR_NO_TOKEN)
return FALSE;
// revert to process token
if (!OpenProcessToken(GetCurrentProcess(),
TOKEN_QUERY|TOKEN_ADJUST_PRIVILEGES,
&hToken))
return FALSE;
}
Priv.PrivilegeCount = 1;
if (bEnable)
Priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
else
Priv.Privileges[0].Attributes = 0;
LookupPrivilegeValue(NULL, pszPrivilegeName, &Priv.Privileges[0].Luid);
// try to enable the privilege
if (!AdjustTokenPrivileges(hToken, FALSE, &Priv, sizeof(Priv),
&PrivOld, &cbPriv))
{
DWORD dwError = GetLastError();
CloseHandle(hToken);
return SetLastError(dwError), FALSE;
}
if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
{
// the privilege is not present in the caller's token
CloseHandle(hToken);
return SetLastError(ERROR_PRIVILEGE_NOT_HELD), FALSE;
}
CloseHandle(hToken);
if (pbPreviousState != NULL)
{
*pbPreviousState =
(PrivOld.Privileges[0].Attributes & SE_PRIVILEGE_ENABLED) != 0;
}
return TRUE;
}
// copies file security
BOOL CopyFileSecurity(
IN PCTSTR pszSourceFileName,
IN PCTSTR pszTargetFileName,
IN ULONG SecurityInformation
)
{
_ASSERTE(pszSourceFileName != NULL);
_ASSERTE(pszTargetFileName != NULL);
DWORD dwRes = ERROR_SUCCESS;
BOOL bPriv, bOldPriv;
BOOL bSaclPrivilege;
PSECURITY_DESCRIPTOR pSecDesc;
// enable SeSecurityPrivilege if we want to manipulate SACL
if (SecurityInformation & SACL_SECURITY_INFORMATION)
EnablePrivilege(SE_SECURITY_NAME, TRUE, &bSaclPrivilege);
// enable SeBackupPrivilege
bPriv = EnablePrivilege(SE_BACKUP_NAME, TRUE, &bOldPriv);
// get source file security descriptor
dwRes = ExGetFileSecurity(pszSourceFileName, SecurityInformation,
bPriv, &pSecDesc);
// restore original state of SeBackupPrivilege
EnablePrivilege(SE_BACKUP_NAME, bOldPriv, NULL);
if (dwRes != ERROR_SUCCESS)
{
// restore original state of SeSecurityPrivilege
if (SecurityInformation & SACL_SECURITY_INFORMATION)
EnablePrivilege(SE_SECURITY_NAME, bSaclPrivilege, NULL);
return SetLastError(dwRes), FALSE;
}
// enable SeRestorePrivilege
bPriv = EnablePrivilege(SE_RESTORE_NAME, TRUE, &bOldPriv);
// assign security information to the target file
dwRes = ExSetFileSecurity(pszTargetFileName, SecurityInformation,
bPriv, pSecDesc);
// restore original state of SeRestorePrivilege
EnablePrivilege(SE_RESTORE_NAME, bOldPriv, NULL);
// restore original state of SeSecurityPrivilege
if (SecurityInformation & SACL_SECURITY_INFORMATION)
EnablePrivilege(SE_SECURITY_NAME, bSaclPrivilege, NULL);
// free security descriptor
LocalFree((HLOCAL)pSecDesc);
if (dwRes != ERROR_SUCCESS)
return SetLastError(dwRes), FALSE;
return TRUE;
}
--- ifmail v.2.15dev5
* Origin: Demos online service (2:5020/400)