Мы поддерживаем DLL, которая делает много системных вещей; обход файловой системы, реестра и т. д. Призыватели этой DLL-библиотеки могут использовать или не использовать олицетворение. Чтобы лучше поддерживать все возможные сценарии, я пытаюсь изменить его, чтобы он был умнее. Я буду использовать пример удаления файла. В настоящее время мы просто вызываем DeleteFile (), и если это не удается, это конец. Я придумал следующее:
BOOL TryReallyHardToDeleteFile(LPCTSTR lpFileName)
{
// 1. caller without privilege
BOOL bSuccess = DeleteFile(lpFileName);
DWORD dwError = GetLastError();
if(!bSuccess && dwError == ERROR_ACCESS_DENIED)
{
// failed with access denied; try with privilege
DWORD dwOldRestorePrivilege = 0;
BOOL bHasRestorePrivilege = SetPrivilege(SE_RESTORE_NAME, SE_PRIVILEGE_ENABLED, &dwOldRestorePrivilege);
if(bHasRestorePrivilege)
{
// 2. caller with privilege
bSuccess = DeleteFile(lpFileName);
dwError = GetLastError();
SetPrivilege(SE_RESTORE_NAME, dwOldRestorePrivilege, NULL);
}
if(!bSuccess && dwError == ERROR_ACCESS_DENIED)
{
// failed with access denied; if caller is impersonating then try as process
HANDLE hToken = NULL;
if(OpenThreadToken(GetCurrentThread(), TOKEN_QUERY | TOKEN_IMPERSONATE, TRUE, &hToken))
{
if(RevertToSelf())
{
// 3. process without privilege
bSuccess = DeleteFile(lpFileName);
dwError = GetLastError();
if(!bSuccess && dwError == ERROR_ACCESS_DENIED)
{
// failed with access denied; try with privilege
bHasRestorePrivilege = SetPrivilege(SE_RESTORE_NAME, SE_PRIVILEGE_ENABLED, &dwOldRestorePrivilege);
if(bHasRestorePrivilege)
{
// 4. process with privilege
bSuccess = DeleteFile(lpFileName);
dwError = GetLastError();
SetPrivilege(SE_RESTORE_NAME, dwOldRestorePrivilege, NULL);
}
}
SetThreadToken(NULL, hToken);
}
CloseHandle(hToken);
hToken = NULL;
}
}
}
if(!bSuccess)
{
SetLastError(dwError);
}
return bSuccess;
}
Итак, сначала он пытается звонить. Если это не удается, когда доступ запрещен, он временно включает привилегии в токене вызывающего абонента и пытается снова. Если произойдет сбой при отказе в доступе, а вызывающий абонент будет выдавать себя за другого, он временно не будет выдавать себя за другого и попытается снова Если произойдет сбой при отказе в доступе, он временно активирует привилегии в маркере процесса и попытается снова. Я думаю, что это должно справиться практически с любой ситуацией, но мне было интересно, есть ли лучший способ добиться этого? Существует множество операций, которые мы потенциально хотели бы использовать этот метод (то есть практически любую операцию, которая обращается к защищаемым объектам).