Compartir a través de


Forzar la eliminación de filtros

En el código de ejemplo siguiente se muestra cómo hacer que un usuario con el privilegio TakeOwnership pueda eliminar un filtro.

Nota

Una aplicación de instalación podría usar esta característica durante una desinstalación para asegurarse de que todos los objetos se eliminan correctamente.

 

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