Condividi tramite


Eliminazione forzata del filtro

Il codice di esempio seguente illustra come rendere un utente con il privilegio TakeOwnership in grado di eliminare un filtro.

Nota

Un'applicazione di installazione potrebbe usare questa funzionalità durante una disinstallazione per assicurarsi che tutti gli oggetti vengano eliminati correttamente.

 

#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;
}