Partager via


Forcer la suppression du filtre

L’exemple de code suivant montre comment rendre un utilisateur disposant du privilège TakeOwnership capable de supprimer un filtre.

Notes

Une application d’installation peut utiliser cette fonctionnalité lors d’une désinstallation pour s’assurer que tous les objets sont supprimés avec succès.

 

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