Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
The following sample code demonstrates how to use the resource assignment layers to reserve a range of ports for administrators.
#include <windows.h>
#include <sddl.h>
#include <fwpmu.h>
#include <stdio.h>
#pragma comment(lib, "fwpuclnt.lib")
#pragma comment(lib, "advapi32.lib")
#define EXIT_ON_ERROR(fnName) \
if (result != ERROR_SUCCESS) \
{ \
printf(#fnName " = 0x%08X\n", result); \
goto CLEANUP; \
}
#define EXIT_ON_LAST_ERROR(success, fnName) \
if (!(success)) \
{ \
result = GetLastError(); \
printf(#fnName " = 0x%08X\n", result); \
goto CLEANUP; \
}
DWORD ReservePortRangeForAdmins(
__in HANDLE engine,
__in PCWSTR filterName,
__in_opt const GUID* providerKey,
__in_opt const GUID* subLayerKey,
__in UINT16 loPort,
__in UINT16 hiPort
)
{
DWORD result = ERROR_SUCCESS;
FWPM_FILTER_CONDITION0 conds[2];
FWP_RANGE0 portRange;
BOOL success;
PSECURITY_DESCRIPTOR sd = NULL;
FWP_BYTE_BLOB sdBlob;
FWPM_FILTER0 filter;
BOOL txnInProgress = FALSE;
//////////
// The first condition matches any local port in the desired range.
//////////
portRange.valueLow.type = FWP_UINT16;
portRange.valueLow.uint16 = loPort;
portRange.valueHigh.type = FWP_UINT16;
portRange.valueHigh.uint16 = hiPort;
conds[0].fieldKey = FWPM_CONDITION_IP_LOCAL_PORT;
conds[0].matchType = FWP_MATCH_RANGE;
conds[0].conditionValue.type = FWP_RANGE_TYPE;
conds[0].conditionValue.rangeValue = &portRange;
//////////
// The second condition matches any user who is a member of the built-in
// Administrators group.
//////////
// For well-known security descriptors, it's easiest to build them in one
// shot from an SDDL string, rather than constructing them programmatically
// using lower-level APIs.
success = ConvertStringSecurityDescriptorToSecurityDescriptorW(
L"D:(A;;0x1;;;BA)",
SDDL_REVISION_1,
&sd,
NULL
);
EXIT_ON_LAST_ERROR(
success,
ConvertStringSecurityDescriptorToSecurityDescriptorW
);
// Security descriptors must be in self-relative form (i.e., contiguous).
// The security descriptor returned by
// ConvertStringSecurityDescriptorToSecurityDescriptorW is already
// self-relative, but if you're using another mechanism to build the
// descriptor, you may have to convert it. See MakeSelfRelativeSD for
// details.
sdBlob.size = GetSecurityDescriptorLength(sd);
sdBlob.data = (UINT8*)sd;
conds[1].fieldKey = FWPM_CONDITION_ALE_USER_ID;
conds[1].matchType = FWP_MATCH_EQUAL;
conds[1].conditionValue.type = FWP_SECURITY_DESCRIPTOR_TYPE;
conds[1].conditionValue.sd = &sdBlob;
// Fill in the common fields shared by all our filters.
memset(&filter, 0, sizeof(filter));
// For MUI compatibility, object names should be indirect strings. See
// SHLoadIndirectString for details.
filter.displayData.name = (PWSTR)filterName;
// Link all objects to our provider. When multiple providers are installed
// on a computer, this makes it easy to determine who added what.
filter.providerKey = (GUID*)providerKey;
// Generally, it's best to add filters to our own sublayer, so we don't have
// to worry about being overridden by filters added by another provider.
if (subLayerKey != NULL)
{
filter.subLayerKey = *subLayerKey;
}
filter.filterCondition = conds;
// We add all the filters from within a single transaction to make it easy
// to clean up partial results in error paths.
result = FwpmTransactionBegin0(engine, 0);
EXIT_ON_ERROR(FwpmTransactionBegin0);
txnInProgress = TRUE;
// Add the filters for IPv4.
filter.layerKey = FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4;
// This filter just has the port range condition, so it blocks all users for
// the desired port range.
filter.numFilterConditions = 1;
filter.action.type = FWP_ACTION_BLOCK;
result = FwpmFilterAdd0(engine, &filter, NULL, NULL);
EXIT_ON_ERROR(FwpmFilterAdd0);
// This filter permits Administrators for the port range. Since we're using
// auto-weighting and this filter is more specific than the previous, it
// will have a higher weight. When an admin tries to bind to a port in the
// range, this filter will match first, permitting the bind. When a
// non-admin tries, this filter won't match and the previous filter will
// block the bind.
filter.numFilterConditions = 2;
filter.action.type = FWP_ACTION_PERMIT;
result = FwpmFilterAdd0(engine, &filter, NULL, NULL);
EXIT_ON_ERROR(FwpmFilterAdd0);
// Add the same filters for IPv6.
filter.layerKey = FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V6;
filter.numFilterConditions = 1;
filter.action.type = FWP_ACTION_BLOCK;
result = FwpmFilterAdd0(engine, &filter, NULL, NULL);
EXIT_ON_ERROR(FwpmFilterAdd0);
filter.numFilterConditions = 2;
filter.action.type = FWP_ACTION_PERMIT;
result = FwpmFilterAdd0(engine, &filter, NULL, NULL);
EXIT_ON_ERROR(FwpmFilterAdd0);
// Once all the adds have succeeded, we commit the transaction to atomically
// add all the new objects.
result = FwpmTransactionCommit0(engine);
EXIT_ON_ERROR(FwpmTransactionCommit0);
txnInProgress = FALSE;
CLEANUP:
if (txnInProgress)
{
// Abort any transaction still in progress to clean up partial results.
FwpmTransactionAbort0(engine);
}
LocalFree(sd);
return result;
}
Related topics