Forçando a exclusão de filtro
O código de exemplo a seguir demonstra como tornar um usuário com o privilégio TakeOwnership capaz de excluir um filtro.
Observação
Um aplicativo de instalação pode usar esse recurso durante uma desinstalação para garantir que todos os objetos sejam excluídos com êxito.
#include <windows.h>
#include <stdio.h>
#include <accctrl.h>
#include <aclapi.h>
#include <fwpmu.h>
#pragma comment(lib, "fwpuclnt.lib")
#pragma comment(lib, "advapi32.lib")
#define EXIT_ON_ERROR(err) if((err) != ERROR_SUCCESS) {goto CLEANUP;}
#define EXIT_ON_LAST_ERROR(success, fnName) \
if (!(success)) \
{ \
result = GetLastError(); \
printf(#fnName " = 0x%08X\n", result); \
goto CLEANUP; \
}
#define EXIT_ON_ALLOC_FAILURE(ptr, fnName) \
if ((ptr) == NULL) \
{ \
result = ERROR_NOT_ENOUGH_MEMORY; \
printf(#fnName " = ERROR_NOT_ENOUGH_MEMORY\n"); \
goto CLEANUP; \
}
DWORD ForceFilterDeletion(__in const GUID* filterKey)
{
DWORD result = ERROR_SUCCESS;
BOOL success;
HANDLE token = NULL;
DWORD userLen, oldPrivLen;
TOKEN_USER* user = NULL;
TOKEN_PRIVILEGES oldPriv, newPriv;
BOOL takeOwnershipEnabled = FALSE;
HANDLE engine = NULL;
EXPLICIT_ACCESS_W access;
PACL acl = NULL;
// This assumes that the current thread is not impersonating. If it is
// impersonating, you need to call OpenThreadToken instead.
success = OpenProcessToken(
GetCurrentProcess(),
( TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY ),
&token
);
EXIT_ON_LAST_ERROR(success, OpenProcessToken);
// Get our SID -- we'll use this to make ourselves owner.
success = GetTokenInformation(
token,
TokenUser,
NULL,
0,
&userLen
);
result = success ? ERROR_INVALID_DATA : GetLastError();
if (result != ERROR_INSUFFICIENT_BUFFER)
{
EXIT_ON_ERROR(result);
}
user = (TOKEN_USER*)HeapAlloc(GetProcessHeap(), 0, userLen);
EXIT_ON_ALLOC_FAILURE(user, HeapAlloc);
success = GetTokenInformation(
token,
TokenUser,
user,
userLen,
&userLen
);
EXIT_ON_LAST_ERROR(success, GetTokenInformation);
newPriv.PrivilegeCount = 1;
success = LookupPrivilegeValueW(
NULL,
SE_TAKE_OWNERSHIP_NAME,
&(newPriv.Privileges[0].Luid)
);
EXIT_ON_LAST_ERROR(success, LookupPrivilegeValueW);
newPriv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
// Enable the TakeOwnership privilege. This must be done before the call to
// FwpmEngineOpen0. The token used for authentication during the call to
// FwpmEngineOpen0 is used for all future access checks as well.
success = AdjustTokenPrivileges(
token,
FALSE,
&newPriv,
sizeof(oldPriv),
&oldPriv,
&oldPrivLen
);
EXIT_ON_LAST_ERROR(success, AdjustTokenPrivileges);
// Check if anything changed, so we can restore the privilege to its
// previous state.
if (oldPriv.PrivilegeCount == 1)
{
takeOwnershipEnabled = TRUE;
}
// The authentication service should always be RPC_C_AUTHN_DEFAULT.
result = FwpmEngineOpen0(
NULL,
RPC_C_AUTHN_DEFAULT,
NULL,
NULL,
&engine
);
EXIT_ON_ERROR(result);
// Make ourselves owner. This will succeed since anyone with the
// TakeOwnership privilege enabled automatically has WRITE_OWNER access.
result = FwpmFilterSetSecurityInfoByKey0(
engine,
filterKey,
OWNER_SECURITY_INFORMATION,
(const SID*)user->User.Sid,
NULL,
NULL,
NULL
);
EXIT_ON_ERROR(result);
access.grfAccessPermissions = DELETE;
access.grfAccessMode = GRANT_ACCESS;
access.grfInheritance = 0;
BuildTrusteeWithSid(&(access.Trustee), user->User.Sid);
result = SetEntriesInAcl(1, &access, NULL, &acl);
EXIT_ON_ERROR(result);
// Grant ourselves delete access. This will succeed since the owner
// automatically has WRITE_DAC access.
result = FwpmFilterSetSecurityInfoByKey0(
engine,
filterKey,
DACL_SECURITY_INFORMATION,
NULL,
NULL,
acl,
NULL
);
EXIT_ON_ERROR(result);
// Delete the filter. This will succeed since we just granted ourselves
// delete access.
result = FwpmFilterDeleteByKey0(engine, filterKey);
EXIT_ON_ERROR(result);
CLEANUP:
LocalFree(acl);
// FwpmEngineClose0 accepts null engine handles, so we needn't precheck for
// null.
FwpmEngineClose0(engine);
if (takeOwnershipEnabled)
{
newPriv.Privileges[0].Attributes = 0;
AdjustTokenPrivileges(
token,
FALSE,
&newPriv,
0,
NULL,
0
);
}
HeapFree(GetProcessHeap(), 0, user);
if (token != NULL)
{
CloseHandle(token);
}
return result;
}
DWORD wmain(int argc,
wchar_t* argv[])
{
UNREFERENCED_PARAMETER(argc);
UNREFERENCED_PARAMETER(argv);
static const GUID guid = { 0x836a4ff0, 0x7c26, 0x47d2, { 0xb9, 0x6d, 0x68, 0x70, 0xa, 0x98, 0x31, 0x18 } };
// Open a session to the filter engine
HANDLE engineHandle = 0;
// Use dynamic sessions for efficiency and safety:
// - All objects associated with the dynamic session are deleted with one call.
// - Filtering policy objects are deleted even when the application crashes.
FWPM_SESSION0 session;
memset(&session, 0, sizeof(session));
session.flags = FWPM_SESSION_FLAG_DYNAMIC;
session.sessionKey = guid;
DWORD result = FwpmEngineOpen0(NULL, RPC_C_AUTHN_WINNT, NULL, &session, &engineHandle);
EXIT_ON_ERROR(result);
// Add a filter
FWPM_FILTER0 filter;
memset(&filter, 0, sizeof(filter));
filter.filterKey = guid;
filter.displayData.name = L"MihaelaTestFilter";
filter.action.type = FWP_ACTION_BLOCK;
filter.layerKey = FWPM_LAYER_INBOUND_IPPACKET_V4;
result = FwpmFilterAdd0(engineHandle, &filter, NULL, NULL);
EXIT_ON_ERROR(result);
// Delete the newly added filter
result = ForceFilterDeletion(&guid);
EXIT_ON_ERROR(result);
printf("Success.\n");
CLEANUP:
FwpmEngineClose0(engineHandle);
return result;
}