mirror of
https://github.com/ssteelfactor-oss/Kestrel
synced 2026-08-09 13:10:08 +00:00
Initial local project recreation
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"Version": 1,
|
||||
"WorkspaceRootPath": "C:\\Users\\user\\source\\repos\\Kestrel\\",
|
||||
"Documents": [
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{644B764C-A591-4F9E-8E46-7371BE41CD02}|Kestrel.vcxproj|C:\\Users\\user\\source\\repos\\Kestrel\\code\\main.c||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}",
|
||||
"RelativeMoniker": "D:0:0:{644B764C-A591-4F9E-8E46-7371BE41CD02}|Kestrel.vcxproj|solutionrelative:code\\main.c||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{644B764C-A591-4F9E-8E46-7371BE41CD02}|Kestrel.vcxproj|C:\\PROGRAM FILES (X86)\\WINDOWS KITS\\10\\INCLUDE\\10.0.26100.0\\UM\\IADS.H||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
|
||||
}
|
||||
],
|
||||
"DocumentGroupContainers": [
|
||||
{
|
||||
"Orientation": 0,
|
||||
"VerticalTabListWidth": 256,
|
||||
"DocumentGroups": [
|
||||
{
|
||||
"DockedWidth": 200,
|
||||
"SelectedChildIndex": 1,
|
||||
"Children": [
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 1,
|
||||
"Title": "Iads.h",
|
||||
"DocumentMoniker": "C:\\Program Files (x86)\\Windows Kits\\10\\Include\\10.0.26100.0\\um\\Iads.h",
|
||||
"RelativeDocumentMoniker": "..\\..\\..\\..\\..\\Program Files (x86)\\Windows Kits\\10\\Include\\10.0.26100.0\\um\\Iads.h",
|
||||
"ToolTip": "C:\\Program Files (x86)\\Windows Kits\\10\\Include\\10.0.26100.0\\um\\Iads.h",
|
||||
"RelativeToolTip": "..\\..\\..\\..\\..\\Program Files (x86)\\Windows Kits\\10\\Include\\10.0.26100.0\\um\\Iads.h",
|
||||
"ViewState": "AgIAAH8AAAAAAAAAAAAAwIYAAAASAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000680|",
|
||||
"WhenOpened": "2026-05-14T15:59:55.591Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 0,
|
||||
"Title": "main.c",
|
||||
"DocumentMoniker": "C:\\Users\\user\\source\\repos\\Kestrel\\code\\main.c",
|
||||
"RelativeDocumentMoniker": "code\\main.c",
|
||||
"ToolTip": "C:\\Users\\user\\source\\repos\\Kestrel\\code\\main.c",
|
||||
"RelativeToolTip": "code\\main.c",
|
||||
"ViewState": "AgIAABUCAAAAAAAAAIA7wHECAAAZAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000423|",
|
||||
"WhenOpened": "2026-05-13T18:18:47.465Z",
|
||||
"EditorCaption": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"Version": 1,
|
||||
"WorkspaceRootPath": "C:\\Users\\user\\source\\repos\\Kestrel\\",
|
||||
"Documents": [
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{644B764C-A591-4F9E-8E46-7371BE41CD02}|Kestrel.vcxproj|C:\\Users\\user\\source\\repos\\Kestrel\\code\\main.c||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}",
|
||||
"RelativeMoniker": "D:0:0:{644B764C-A591-4F9E-8E46-7371BE41CD02}|Kestrel.vcxproj|solutionrelative:code\\main.c||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
|
||||
}
|
||||
],
|
||||
"DocumentGroupContainers": [
|
||||
{
|
||||
"Orientation": 0,
|
||||
"VerticalTabListWidth": 256,
|
||||
"DocumentGroups": [
|
||||
{
|
||||
"DockedWidth": 200,
|
||||
"SelectedChildIndex": 1,
|
||||
"Children": [
|
||||
{
|
||||
"$type": "Bookmark",
|
||||
"Name": "ST:0:0:{c6f34f0d-7ae5-4f3a-be61-fe0c21ae9eb8}"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 0,
|
||||
"Title": "main.c",
|
||||
"DocumentMoniker": "C:\\Users\\user\\source\\repos\\Kestrel\\code\\main.c",
|
||||
"RelativeDocumentMoniker": "code\\main.c",
|
||||
"ToolTip": "C:\\Users\\user\\source\\repos\\Kestrel\\code\\main.c",
|
||||
"RelativeToolTip": "code\\main.c",
|
||||
"ViewState": "AgIAABACAAAAAAAAAAA2wOgBAAAzAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000423|",
|
||||
"WhenOpened": "2026-05-13T18:18:47.465Z",
|
||||
"EditorCaption": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
+31
@@ -0,0 +1,31 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 18
|
||||
VisualStudioVersion = 18.5.11801.241 oobstable
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Kestrel", "Kestrel.vcxproj", "{644B764C-A591-4F9E-8E46-7371BE41CD02}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{644B764C-A591-4F9E-8E46-7371BE41CD02}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{644B764C-A591-4F9E-8E46-7371BE41CD02}.Debug|x64.Build.0 = Debug|x64
|
||||
{644B764C-A591-4F9E-8E46-7371BE41CD02}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{644B764C-A591-4F9E-8E46-7371BE41CD02}.Debug|x86.Build.0 = Debug|Win32
|
||||
{644B764C-A591-4F9E-8E46-7371BE41CD02}.Release|x64.ActiveCfg = Release|x64
|
||||
{644B764C-A591-4F9E-8E46-7371BE41CD02}.Release|x64.Build.0 = Release|x64
|
||||
{644B764C-A591-4F9E-8E46-7371BE41CD02}.Release|x86.ActiveCfg = Release|Win32
|
||||
{644B764C-A591-4F9E-8E46-7371BE41CD02}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {6E896366-C4D2-486D-B9F4-43C6DA1738B9}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>18.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{644b764c-a591-4f9e-8e46-7371be41cd02}</ProjectGuid>
|
||||
<RootNamespace>Kestrel</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v145</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v145</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v145</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v145</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="code\KestrelACL.C" />
|
||||
<ClCompile Include="code\main.c" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Исходные файлы">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Файлы заголовков">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Файлы ресурсов">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="code\main.c">
|
||||
<Filter>Исходные файлы</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="code\KestrelACL.C">
|
||||
<Filter>Исходные файлы</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup />
|
||||
</Project>
|
||||
@@ -0,0 +1,16 @@
|
||||
c:\users\user\source\repos\kestrel\kestrel\x64\debug\vc145.pdb
|
||||
c:\users\user\source\repos\kestrel\kestrel\x64\debug\vc145.idb
|
||||
c:\users\user\source\repos\kestrel\kestrel\x64\debug\kestrelacl.obj
|
||||
c:\users\user\source\repos\kestrel\kestrel\x64\debug\main.obj
|
||||
c:\users\user\source\repos\kestrel\x64\debug\kestrel.pdb
|
||||
c:\users\user\source\repos\kestrel\kestrel\x64\debug\kestrel.tlog\cl.command.1.tlog
|
||||
c:\users\user\source\repos\kestrel\kestrel\x64\debug\kestrel.tlog\cl.read.1.tlog
|
||||
c:\users\user\source\repos\kestrel\kestrel\x64\debug\kestrel.tlog\cl.write.1.tlog
|
||||
c:\users\user\source\repos\kestrel\kestrel\x64\debug\kestrel.tlog\link-cvtres.read.1.tlog
|
||||
c:\users\user\source\repos\kestrel\kestrel\x64\debug\kestrel.tlog\link-cvtres.write.1.tlog
|
||||
c:\users\user\source\repos\kestrel\kestrel\x64\debug\kestrel.tlog\link-rc.read.1.tlog
|
||||
c:\users\user\source\repos\kestrel\kestrel\x64\debug\kestrel.tlog\link-rc.write.1.tlog
|
||||
c:\users\user\source\repos\kestrel\kestrel\x64\debug\kestrel.tlog\link.command.1.tlog
|
||||
c:\users\user\source\repos\kestrel\kestrel\x64\debug\kestrel.tlog\link.read.1.tlog
|
||||
c:\users\user\source\repos\kestrel\kestrel\x64\debug\kestrel.tlog\link.read.2.tlog
|
||||
c:\users\user\source\repos\kestrel\kestrel\x64\debug\kestrel.tlog\link.write.1.tlog
|
||||
@@ -0,0 +1,9 @@
|
||||
KestrelACL.C
|
||||
main.c
|
||||
Создание кода...
|
||||
C:\Users\user\source\repos\Kestrel\code\main.c(347,9): warning C4013: StringCchPrintfW: нет определения; предполагается "extern" с возвратом типа "int"
|
||||
C:\Users\user\source\repos\Kestrel\code\main.c(467,9): warning C4013: StringCchCopyW: нет определения; предполагается "extern" с возвратом типа "int"
|
||||
main.obj : error LNK2019: ссылка на неразрешенный внешний символ StringCchCopyW в функции KestrelWalkDacl.
|
||||
odbccp32.lib(dllload.obj) : error LNK2019: ссылка на неразрешенный внешний символ _vsnwprintf_s в функции StringCchPrintfW.
|
||||
MSVCRTD.lib(exe_main.obj) : error LNK2019: ссылка на неразрешенный внешний символ main в функции "int __cdecl invoke_main(void)" (?invoke_main@@YAHXZ).
|
||||
C:\Users\user\source\repos\Kestrel\x64\Debug\Kestrel.exe : fatal error LNK1120: неразрешенных внешних элементов: 3
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,2 @@
|
||||
PlatformToolSet=v145:VCToolArchitecture=Native64Bit:VCToolsVersion=14.50.35717:VCServicingVersionCompilers=14.50.35730:TargetPlatformVersion=10.0.26100.0:VcpkgTriplet=x64-windows:
|
||||
Debug|x64|C:\Users\user\source\repos\Kestrel\|
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+630
@@ -0,0 +1,630 @@
|
||||
/*
|
||||
* Kestrel_ACL.c — v0.2
|
||||
* ACL edge extraction via IDirectoryObject / SECURITY_DESCRIPTOR
|
||||
*
|
||||
* Three phases:
|
||||
* 1. Build Extended Rights GUID→name table from CN=Extended-Rights,CN=Configuration
|
||||
* 2. Enumerate all relevant AD objects, retrieve raw nTSecurityDescriptor
|
||||
* 3. Walk DACL per object, classify ACEs into typed edges
|
||||
*
|
||||
* All queries run through ADSI COM interfaces (IDirectorySearch, IDirectoryObject).
|
||||
* No .NET, no PowerShell, no managed runtime.
|
||||
* SAL 2.0 annotations validated by /analyze (PREfast).
|
||||
*
|
||||
* rootDSE (defaultNamingContext, configurationNamingContext) is resolved once
|
||||
* by the caller and passed as parameters — never re-queried inside this module.
|
||||
*/
|
||||
|
||||
#define COBJMACROS
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <oleauto.h>
|
||||
#include <activeds.h> /* ADSI COM interfaces */
|
||||
#include <adshlp.h> /* ADsGetObject, ADsOpenObject */
|
||||
#include <iads.h> /* IDirectoryObject, IDirectorySearch */
|
||||
#include <adserr.h> /* HRESULT_FROM_WIN32 helpers */
|
||||
#include <sddl.h> /* ConvertSidToStringSidW */
|
||||
#include <accctrl.h> /* EXPLICIT_ACCESS, TRUSTEE */
|
||||
#include <aclapi.h> /* GetSecurityDescriptorDacl */
|
||||
#include <sal.h>
|
||||
|
||||
/* ─────────────────────────────────────────────────────────────────────────── */
|
||||
/* Constants */
|
||||
/* ─────────────────────────────────────────────────────────────────────────── */
|
||||
|
||||
/* Full-scope object filter — all types that carry meaningful ACL edges */
|
||||
#define KESTREL_ACL_FILTER \
|
||||
L"(|(objectClass=user)(objectClass=group)(objectClass=computer)" \
|
||||
L"(objectClass=organizationalUnit)(objectClass=domainDNS)" \
|
||||
L"(objectClass=container)(objectClass=groupPolicyContainer)" \
|
||||
L"(objectClass=builtinDomain))"
|
||||
|
||||
/* Attributes fetched per object via IDirectorySearch */
|
||||
static LPWSTR g_rgszObjectAttrs[] = {
|
||||
L"distinguishedName",
|
||||
L"objectClass",
|
||||
L"objectSid",
|
||||
L"nTSecurityDescriptor"
|
||||
};
|
||||
#define KESTREL_OBJECT_ATTR_COUNT \
|
||||
(sizeof(g_rgszObjectAttrs) / sizeof(g_rgszObjectAttrs[0]))
|
||||
|
||||
/* Attributes fetched per Extended Right entry */
|
||||
static LPWSTR g_rgszRightAttrs[] = {
|
||||
L"rightsGuid",
|
||||
L"displayName",
|
||||
L"appliesTo"
|
||||
};
|
||||
#define KESTREL_RIGHT_ATTR_COUNT \
|
||||
(sizeof(g_rgszRightAttrs) / sizeof(g_rgszRightAttrs[0]))
|
||||
|
||||
/* Well-known GUID strings used in ACE ObjectType comparison */
|
||||
/* DS-Replication-Get-Changes — DCSync component */
|
||||
#define GUID_DS_REPL_GET_CHANGES L"{1131f6aa-9c07-11d1-f79f-00c04fc2dcd2}"
|
||||
/* DS-Replication-Get-Changes-All — DCSync component */
|
||||
#define GUID_DS_REPL_GET_CHANGES_ALL L"{1131f6ab-9c07-11d1-f79f-00c04fc2dcd2}"
|
||||
/* User-Force-Change-Password */
|
||||
#define GUID_FORCE_CHANGE_PASSWORD L"{00299570-246d-11d0-a768-00aa006e0529}"
|
||||
/* Self-Membership (write to member attr on groups) */
|
||||
#define GUID_SELF_MEMBERSHIP L"{bf9679c0-0de6-11d0-a285-00aa003049e2}"
|
||||
/* ms-DS-Allowed-To-Act-On-Behalf-Of-Other-Identity (RBCD write) */
|
||||
#define GUID_ALLOWED_TO_ACT_ON_BEHALF L"{3f78c3e5-f79a-46bd-a0b8-9d18116ddc79}"
|
||||
|
||||
/* Most Generic ADS Rights — bitmask of all possible الحقوق */
|
||||
#define ADS_RIGHT_ALL (ADS_RIGHT_READ_PROP | \
|
||||
ADS_RIGHT_WRITE_PROP | \
|
||||
ADS_RIGHT_APPEND | \
|
||||
ADS_RIGHT_READ_ATTRS | \
|
||||
ADS_RIGHT_WRITE_ATTRS | \
|
||||
ADS_RIGHT_CREATE_CHILD | \
|
||||
ADS_RIGHT_DELETE_CHILD | \
|
||||
ADS_RIGHT_READ_OWN | \
|
||||
ADS_RIGHT_WRITE_OWN | \
|
||||
ADS_RIGHT_READ_ACL | \
|
||||
ADS_RIGHT_WRITE_ACL | \
|
||||
ADS_RIGHT_DELETE | \
|
||||
ADS_RIGHT_EXECUTE | \
|
||||
ADS_RIGHT_CONTROL | \
|
||||
ADS_RIGHT_GENERIC_ALL )
|
||||
|
||||
/* ─────────────────────────────────────────────────────────────────────────── */
|
||||
/* Data structures */
|
||||
/* ─────────────────────────────────────────────────────────────────────────── */
|
||||
|
||||
/*
|
||||
* KESTREL_EXTENDED_RIGHT
|
||||
* One entry in the Extended Rights table.
|
||||
* appliesTo is a NULL-terminated array of class GUIDs (schema objects
|
||||
* this right is defined on — e.g. user, group, computer).
|
||||
*/
|
||||
typedef struct _KESTREL_EXTENDED_RIGHT {
|
||||
WCHAR wszGuid[64]; /* rightsGuid canonical form, e.g. {xxxxxxxx-...} */
|
||||
WCHAR wszDisplayName[128];/* human-readable name, e.g. "User-Force-Change-Password" */
|
||||
WCHAR** rgwszAppliesTo; /* NULL-terminated array of schema class GUIDs */
|
||||
DWORD cAppliesTo;
|
||||
struct _KESTREL_EXTENDED_RIGHT* pNext;
|
||||
} KESTREL_EXTENDED_RIGHT;
|
||||
|
||||
/*
|
||||
* KESTREL_ACL_EDGE_TYPE
|
||||
* Semantic classification of an ACE into an attack-graph edge category.
|
||||
*/
|
||||
typedef enum _KESTREL_ACL_EDGE_TYPE {
|
||||
EDGE_UNKNOWN = 0,
|
||||
EDGE_GENERIC_ALL = 1, /* ADS_RIGHT_GENERIC_ALL or 0xF01FF */
|
||||
EDGE_WRITE_DACL = 2, /* ADS_RIGHT_WRITE_DAC */
|
||||
EDGE_WRITE_OWNER = 3, /* ADS_RIGHT_ACTRL_DS_LIST_OBJECT / WRITE_OWNER */
|
||||
EDGE_GENERIC_WRITE = 4, /* ADS_RIGHT_GENERIC_WRITE */
|
||||
EDGE_EXTENDED_RIGHT = 5, /* ADS_RIGHT_DS_CONTROL_ACCESS + GUID */
|
||||
EDGE_WRITE_PROPERTY = 6, /* ADS_RIGHT_DS_WRITE_PROP + GUID */
|
||||
EDGE_CREATE_CHILD = 7, /* ADS_RIGHT_DS_CREATE_CHILD */
|
||||
EDGE_DELETE_CHILD = 8, /* ADS_RIGHT_DS_DELETE_CHILD */
|
||||
EDGE_SELF = 9, /* ADS_RIGHT_DS_SELF (self-write) */
|
||||
} KESTREL_ACL_EDGE_TYPE;
|
||||
|
||||
/*
|
||||
* KESTREL_ACL_EDGE
|
||||
* One resolved edge in the access-control graph.
|
||||
* trustee → target, via right encoded in EdgeType + (optional) wszRightName.
|
||||
*/
|
||||
typedef struct _KESTREL_ACL_EDGE {
|
||||
WCHAR wszTrusteeSid[128]; /* string SID of ACE trustee */
|
||||
WCHAR wszTargetDN[512]; /* DN of the object bearing the ACE */
|
||||
WCHAR wszObjectClass[64]; /* objectClass of target */
|
||||
KESTREL_ACL_EDGE_TYPE EdgeType;
|
||||
WCHAR wszRightName[128]; /* displayName if EDGE_EXTENDED_RIGHT/WRITE_PROP */
|
||||
WCHAR wszRightGuid[64]; /* raw GUID for WRITE_PROPERTY edges */
|
||||
BOOL bInherited; /* ACE_INHERITED flag */
|
||||
BOOL bDeny; /* ACCESS_DENIED_OBJECT_ACE_TYPE */
|
||||
} KESTREL_ACL_EDGE;
|
||||
|
||||
/*
|
||||
* KESTREL_ACL_SCAN_RESULT
|
||||
* Flat array of edges produced by KestrelScanACLEdges.
|
||||
* cEdges may reach tens of thousands on a large domain.
|
||||
*/
|
||||
typedef struct _KESTREL_ACL_SCAN_RESULT {
|
||||
KESTREL_ACL_EDGE* rgEdges;
|
||||
DWORD cEdges;
|
||||
DWORD cCapacity; /* allocated slots */
|
||||
DWORD cObjectsScanned;
|
||||
DWORD cObjectsErrored;
|
||||
} KESTREL_ACL_SCAN_RESULT;
|
||||
|
||||
/* ─────────────────────────────────────────────────────────────────────────── */
|
||||
/* Forward declarations (SAL 2.0 annotated) */
|
||||
/* ─────────────────────────────────────────────────────────────────────────── */
|
||||
|
||||
/*
|
||||
* Phase 1 — Build Extended Rights lookup table.
|
||||
*
|
||||
* Queries CN=Extended-Rights,CN=Configuration,<configNC> via IDirectorySearch.
|
||||
* Allocates a singly-linked list of KESTREL_EXTENDED_RIGHT entries on the heap.
|
||||
* Caller must free via KestrelFreeExtendedRightsTable.
|
||||
*
|
||||
* Parameters:
|
||||
* pwszConfigNC — configurationNamingContext from rootDSE (caller-owned)
|
||||
* ppRightsHead — receives pointer to head of list; NULL on failure
|
||||
*
|
||||
* Returns:
|
||||
* S_OK — table built successfully (list may still be empty if
|
||||
* CN=Extended-Rights is empty or inaccessible)
|
||||
* HRESULT error — LDAP bind failed, ADsGetObject error, or allocation failure
|
||||
*/
|
||||
_Must_inspect_result_
|
||||
HRESULT
|
||||
KestrelBuildExtendedRightsTable(
|
||||
_In_z_ LPCWSTR pwszConfigNC,
|
||||
_Outptr_result_maybenull_
|
||||
KESTREL_EXTENDED_RIGHT** ppRightsHead
|
||||
);
|
||||
|
||||
/*
|
||||
* Resolve an Extended Right GUID to its displayName.
|
||||
* Linear scan — table is small enough (~200 entries) that hashing is unnecessary.
|
||||
*
|
||||
* Returns pointer to entry if found, NULL if GUID is not in the table.
|
||||
* Returned pointer is valid for the lifetime of pRightsHead.
|
||||
*/
|
||||
_Ret_maybenull_
|
||||
const KESTREL_EXTENDED_RIGHT*
|
||||
KestrelLookupExtendedRight(
|
||||
_In_ const KESTREL_EXTENDED_RIGHT* pRightsHead,
|
||||
_In_z_ LPCWSTR pwszGuid
|
||||
);
|
||||
|
||||
/*
|
||||
* Phase 2 — Retrieve raw nTSecurityDescriptor for one AD object.
|
||||
*
|
||||
* Uses IDirectoryObject::GetObjectAttributes with attribute "nTSecurityDescriptor".
|
||||
* The returned SECURITY_DESCRIPTOR is allocated by ADSI; caller must call
|
||||
* FreeADsMem on *ppSD when done.
|
||||
*
|
||||
* Parameters:
|
||||
* pDirObj — bound IDirectoryObject for the target object
|
||||
* ppSD — receives pointer to SECURITY_DESCRIPTOR; NULL on failure
|
||||
* pcbSD — receives byte length of the returned SD
|
||||
*/
|
||||
_Must_inspect_result_
|
||||
HRESULT
|
||||
KestrelGetObjectSecurityDescriptor(
|
||||
_In_ IDirectoryObject* pDirObj,
|
||||
_Outptr_ PSECURITY_DESCRIPTOR* ppSD,
|
||||
_Out_ DWORD* pcbSD
|
||||
);
|
||||
|
||||
/*
|
||||
* Phase 3 — Walk DACL and emit edges into result buffer.
|
||||
*
|
||||
* Iterates every ACE in pDacl. Filters out INHERIT_ONLY ACEs that do not
|
||||
* apply to the object itself. Classifies each ACE and appends one
|
||||
* KESTREL_ACL_EDGE to pResult per significant right found.
|
||||
*
|
||||
* Significant = GenericAll / WriteDacl / WriteOwner / GenericWrite /
|
||||
* ExtendedRight (DS_CONTROL_ACCESS) / WriteProperty (DS_WRITE_PROP)
|
||||
* on a named attribute GUID / CreateChild / DeleteChild.
|
||||
*
|
||||
* Parameters:
|
||||
* pDacl — pointer to DACL extracted from object's SD
|
||||
* pwszTargetDN — DN of the object (for edge annotation)
|
||||
* pwszObjectClass — objectClass of the object (for edge annotation)
|
||||
* pRightsHead — Extended Rights table (may be NULL; GUIDs emitted raw)
|
||||
* pResult — output buffer; KestrelACLResultAppend reallocates as needed
|
||||
*/
|
||||
_Must_inspect_result_
|
||||
HRESULT
|
||||
KestrelWalkDacl(
|
||||
_In_ PACL pDacl,
|
||||
_In_z_ LPCWSTR pwszTargetDN,
|
||||
_In_z_ LPCWSTR pwszObjectClass,
|
||||
_In_opt_ const KESTREL_EXTENDED_RIGHT* pRightsHead,
|
||||
_Inout_ KESTREL_ACL_SCAN_RESULT* pResult
|
||||
);
|
||||
|
||||
/*
|
||||
* Main entry point — orchestrates all three phases across the full domain.
|
||||
*
|
||||
* Executes IDirectorySearch with KESTREL_ACL_FILTER against pwszDomainNC.
|
||||
* For each result object: binds IDirectoryObject, retrieves SD, walks DACL.
|
||||
*
|
||||
* Parameters:
|
||||
* pwszDomainNC — defaultNamingContext from rootDSE
|
||||
* pwszConfigNC — configurationNamingContext from rootDSE
|
||||
* ppResult — receives allocated KESTREL_ACL_SCAN_RESULT; free via
|
||||
* KestrelFreeACLScanResult
|
||||
*
|
||||
* Returns S_OK even if some objects errored (check pResult->cObjectsErrored).
|
||||
* Returns failure HRESULT only if the LDAP search itself cannot be initiated.
|
||||
*/
|
||||
_Must_inspect_result_
|
||||
HRESULT
|
||||
KestrelScanACLEdges(
|
||||
_In_z_ LPCWSTR pwszDomainNC,
|
||||
_In_z_ LPCWSTR pwszConfigNC,
|
||||
_Outptr_ KESTREL_ACL_SCAN_RESULT** ppResult
|
||||
);
|
||||
|
||||
/* ─────────────────────────────────────────────────────────────────────────── */
|
||||
/* Internal helpers (not exported) */
|
||||
/* ─────────────────────────────────────────────────────────────────────────── */
|
||||
|
||||
/*
|
||||
* Grow pResult->rgEdges if needed and append one edge.
|
||||
* Initial capacity: 4096 edges; grows by doubling.
|
||||
*/
|
||||
_Must_inspect_result_
|
||||
static HRESULT
|
||||
KestrelACLResultAppend(
|
||||
_Inout_ KESTREL_ACL_SCAN_RESULT* pResult,
|
||||
_In_ const KESTREL_ACL_EDGE* pEdge
|
||||
);
|
||||
|
||||
/*
|
||||
* Translate ACCESS_MASK bits to KESTREL_ACL_EDGE_TYPE.
|
||||
* Returns EDGE_UNKNOWN if the mask carries no significant right.
|
||||
* For DS_CONTROL_ACCESS / DS_WRITE_PROP, also emits GUID if pObjectTypeGuid != NULL.
|
||||
*/
|
||||
static KESTREL_ACL_EDGE_TYPE
|
||||
KestrelClassifyAccessMask(
|
||||
_In_ DWORD dwAccessMask,
|
||||
_In_opt_ GUID* pObjectTypeGuid
|
||||
);
|
||||
|
||||
/*
|
||||
* Format a GUID struct to the canonical string form {xxxxxxxx-xxxx-...}.
|
||||
* pwszBuf must be at least 40 characters.
|
||||
*/
|
||||
static VOID
|
||||
KestrelGuidToString(
|
||||
_In_ const GUID* pGuid,
|
||||
_Out_writes_z_(cchBuf) LPWSTR pwszBuf,
|
||||
_In_ SIZE_T cchBuf
|
||||
);
|
||||
|
||||
/* ─────────────────────────────────────────────────────────────────────────── */
|
||||
/* Cleanup */
|
||||
/* ─────────────────────────────────────────────────────────────────────────── */
|
||||
|
||||
/*
|
||||
* Free the singly-linked Extended Rights list built by
|
||||
* KestrelBuildExtendedRightsTable. Safe to call with NULL.
|
||||
*/
|
||||
VOID
|
||||
KestrelFreeExtendedRightsTable(
|
||||
_In_opt_ _Post_ptr_invalid_ KESTREL_EXTENDED_RIGHT* pRightsHead
|
||||
);
|
||||
|
||||
/*
|
||||
* Free scan result and all contained edge data.
|
||||
* Safe to call with NULL.
|
||||
*/
|
||||
VOID
|
||||
KestrelFreeACLScanResult(
|
||||
_In_opt_ _Post_ptr_invalid_ KESTREL_ACL_SCAN_RESULT* pResult
|
||||
);
|
||||
|
||||
/* ─────────────────────────────────────────────────────────────────────────── */
|
||||
/* Implementation stubs */
|
||||
/* ─────────────────────────────────────────────────────────────────────────── */
|
||||
|
||||
_Must_inspect_result_
|
||||
HRESULT
|
||||
KestrelBuildExtendedRightsTable(
|
||||
_In_z_ LPCWSTR pwszConfigNC,
|
||||
_Outptr_result_maybenull_
|
||||
KESTREL_EXTENDED_RIGHT** ppRightsHead)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
IDirectorySearch* pSearch = NULL;
|
||||
ADS_SEARCH_HANDLE hSearch = NULL;
|
||||
KESTREL_EXTENDED_RIGHT* pHead = NULL;
|
||||
WCHAR wszPath[512];
|
||||
|
||||
if (!pwszConfigNC || !ppRightsHead) return E_INVALIDARG;
|
||||
*ppRightsHead = NULL;
|
||||
|
||||
/* Build LDAP path to CN=Extended-Rights */
|
||||
if (FAILED(StringCchPrintfW(wszPath, ARRAYSIZE(wszPath),
|
||||
L"LDAP://CN=Extended-Rights,%s", pwszConfigNC)))
|
||||
return E_UNEXPECTED;
|
||||
|
||||
/* TODO: ADsGetObject → IDirectorySearch */
|
||||
/* TODO: SetSearchPreference (SCOPE_ONELEVEL, PAGESIZE=200) */
|
||||
/* TODO: ExecuteSearch with filter "(objectClass=controlAccessRight)" */
|
||||
/* TODO: loop GetNextRow → GetColumn(rightsGuid/displayName/appliesTo) */
|
||||
/* TODO: allocate and link KESTREL_EXTENDED_RIGHT per row */
|
||||
|
||||
*ppRightsHead = pHead;
|
||||
return hr;
|
||||
}
|
||||
|
||||
_Ret_maybenull_
|
||||
const KESTREL_EXTENDED_RIGHT*
|
||||
KestrelLookupExtendedRight(
|
||||
_In_ const KESTREL_EXTENDED_RIGHT* pRightsHead,
|
||||
_In_z_ LPCWSTR pwszGuid)
|
||||
{
|
||||
for (const KESTREL_EXTENDED_RIGHT* p = pRightsHead; p; p = p->pNext) {
|
||||
if (_wcsicmp(p->wszGuid, pwszGuid) == 0)
|
||||
return p;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
HRESULT
|
||||
KestrelGetObjectSecurityDescriptor(
|
||||
_In_ IDirectoryObject* pDirObj,
|
||||
_Outptr_ PSECURITY_DESCRIPTOR* ppSD,
|
||||
_Out_ DWORD* pcbSD)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
ADS_ATTR_INFO* pAttrInfo = NULL;
|
||||
DWORD cAttrs = 0;
|
||||
LPWSTR rgszAttrs[] = { L"nTSecurityDescriptor" };
|
||||
|
||||
if (!pDirObj || !ppSD || !pcbSD) return E_INVALIDARG;
|
||||
*ppSD = NULL;
|
||||
*pcbSD = 0;
|
||||
|
||||
/* TODO: pDirObj->lpVtbl->GetObjectAttributes(pDirObj, rgszAttrs, 1, &pAttrInfo, &cAttrs) */
|
||||
/* TODO: verify cAttrs == 1 && pAttrInfo[0].pADsValues->dwType == ADSTYPE_PROV_SPECIFIC */
|
||||
/* TODO: extract lpValue / dwLength from ADS_PROV_SPECIFIC */
|
||||
/* TODO: *ppSD = (PSECURITY_DESCRIPTOR)pAttrInfo[0].pADsValues->ProviderSpecific.lpValue */
|
||||
/* TODO: *pcbSD = pAttrInfo[0].pADsValues->ProviderSpecific.dwLength */
|
||||
/* Note: caller frees pAttrInfo via FreeADsMem; *ppSD is a pointer into pAttrInfo */
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
HRESULT
|
||||
KestrelWalkDacl(
|
||||
_In_ PACL pDacl,
|
||||
_In_z_ LPCWSTR pwszTargetDN,
|
||||
_In_z_ LPCWSTR pwszObjectClass,
|
||||
_In_opt_ const KESTREL_EXTENDED_RIGHT* pRightsHead,
|
||||
_Inout_ KESTREL_ACL_SCAN_RESULT* pResult)
|
||||
{
|
||||
if (!pDacl || !pwszTargetDN || !pwszObjectClass || !pResult)
|
||||
return E_INVALIDARG;
|
||||
|
||||
ACL_SIZE_INFORMATION aclInfo = { 0 };
|
||||
if (!GetAclInformation(pDacl, &aclInfo, sizeof(aclInfo), AclSizeInformation))
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
|
||||
for (DWORD i = 0; i < aclInfo.AceCount; i++) {
|
||||
LPVOID pAce = NULL;
|
||||
if (!GetAce(pDacl, i, &pAce)) continue;
|
||||
|
||||
ACE_HEADER* pHeader = (ACE_HEADER*)pAce;
|
||||
BOOL bDeny = (pHeader->AceType == ACCESS_DENIED_ACE_TYPE ||
|
||||
pHeader->AceType == ACCESS_DENIED_OBJECT_ACE_TYPE);
|
||||
|
||||
/* Skip pure inherit-only ACEs — they do not apply to the object itself */
|
||||
if ((pHeader->AceFlags & INHERIT_ONLY_ACE) &&
|
||||
!(pHeader->AceFlags & OBJECT_INHERIT_ACE))
|
||||
continue;
|
||||
|
||||
DWORD dwMask = 0;
|
||||
PSID pTrusteeSid = NULL;
|
||||
GUID* pObjectType = NULL;
|
||||
|
||||
switch (pHeader->AceType) {
|
||||
case ACCESS_ALLOWED_ACE_TYPE:
|
||||
case ACCESS_DENIED_ACE_TYPE: {
|
||||
ACCESS_ALLOWED_ACE* p = (ACCESS_ALLOWED_ACE*)pAce;
|
||||
dwMask = p->Mask;
|
||||
pTrusteeSid = (PSID)&p->SidStart;
|
||||
break;
|
||||
}
|
||||
case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
|
||||
case ACCESS_DENIED_OBJECT_ACE_TYPE: {
|
||||
ACCESS_ALLOWED_OBJECT_ACE* p = (ACCESS_ALLOWED_OBJECT_ACE*)pAce;
|
||||
dwMask = p->Mask;
|
||||
if (p->Flags & ACE_OBJECT_TYPE_PRESENT)
|
||||
pObjectType = &p->ObjectType;
|
||||
/* SidStart offset depends on which GUIDs are present */
|
||||
pTrusteeSid = (PSID)((BYTE*)p + sizeof(ACCESS_ALLOWED_OBJECT_ACE) -
|
||||
sizeof(GUID) *
|
||||
(2 - !!(p->Flags & ACE_OBJECT_TYPE_PRESENT)
|
||||
- !!(p->Flags & ACE_INHERITED_OBJECT_TYPE_PRESENT)));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
continue; /* SYSTEM_AUDIT_*, etc. — not relevant here */
|
||||
}
|
||||
|
||||
KESTREL_ACL_EDGE_TYPE edgeType = KestrelClassifyAccessMask(dwMask, pObjectType);
|
||||
if (edgeType == EDGE_UNKNOWN) continue;
|
||||
|
||||
/* Build the edge record */
|
||||
KESTREL_ACL_EDGE edge = { 0 };
|
||||
edge.EdgeType = edgeType;
|
||||
edge.bDeny = bDeny;
|
||||
edge.bInherited = !!(pHeader->AceFlags & INHERITED_ACE);
|
||||
|
||||
StringCchCopyW(edge.wszTargetDN, ARRAYSIZE(edge.wszTargetDN), pwszTargetDN);
|
||||
StringCchCopyW(edge.wszObjectClass, ARRAYSIZE(edge.wszObjectClass), pwszObjectClass);
|
||||
|
||||
/* TODO: ConvertSidToStringSidW(pTrusteeSid, &pwszSid) → edge.wszTrusteeSid */
|
||||
|
||||
if (pObjectType && (edgeType == EDGE_EXTENDED_RIGHT || edgeType == EDGE_WRITE_PROPERTY)) {
|
||||
KestrelGuidToString(pObjectType, edge.wszRightGuid, ARRAYSIZE(edge.wszRightGuid));
|
||||
const KESTREL_EXTENDED_RIGHT* pRight = KestrelLookupExtendedRight(pRightsHead, edge.wszRightGuid);
|
||||
if (pRight)
|
||||
StringCchCopyW(edge.wszRightName, ARRAYSIZE(edge.wszRightName), pRight->wszDisplayName);
|
||||
}
|
||||
|
||||
HRESULT hr = KestrelACLResultAppend(pResult, &edge);
|
||||
if (FAILED(hr)) return hr;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
HRESULT
|
||||
KestrelScanACLEdges(
|
||||
_In_z_ LPCWSTR pwszDomainNC,
|
||||
_In_z_ LPCWSTR pwszConfigNC,
|
||||
_Outptr_ KESTREL_ACL_SCAN_RESULT** ppResult)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
KESTREL_EXTENDED_RIGHT* pRights = NULL;
|
||||
KESTREL_ACL_SCAN_RESULT* pResult = NULL;
|
||||
IDirectorySearch* pSearch = NULL;
|
||||
ADS_SEARCH_HANDLE hSearch = NULL;
|
||||
WCHAR wszPath[512];
|
||||
|
||||
if (!pwszDomainNC || !pwszConfigNC || !ppResult) return E_INVALIDARG;
|
||||
*ppResult = NULL;
|
||||
|
||||
/* Allocate result container */
|
||||
pResult = (KESTREL_ACL_SCAN_RESULT*)HeapAlloc(GetProcessHeap(),
|
||||
HEAP_ZERO_MEMORY,
|
||||
sizeof(*pResult));
|
||||
if (!pResult) return E_OUTOFMEMORY;
|
||||
|
||||
/* Phase 1: Extended Rights table */
|
||||
hr = KestrelBuildExtendedRightsTable(pwszConfigNC, &pRights);
|
||||
if (FAILED(hr)) goto Cleanup;
|
||||
|
||||
/* Build LDAP root path */
|
||||
if (FAILED(StringCchPrintfW(wszPath, ARRAYSIZE(wszPath),
|
||||
L"LDAP://%s", pwszDomainNC))) {
|
||||
hr = E_UNEXPECTED;
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
/* TODO: ADsGetObject(wszPath, IID_IDirectorySearch, &pSearch) */
|
||||
/* TODO: SetSearchPreference:
|
||||
ADS_SEARCHPREF_SEARCH_SCOPE = ADS_SCOPE_SUBTREE
|
||||
ADS_SEARCHPREF_PAGESIZE = 200
|
||||
ADS_SEARCHPREF_SECURITY_MASK = (OWNER_SECURITY_INFORMATION |
|
||||
GROUP_SECURITY_INFORMATION |
|
||||
DACL_SECURITY_INFORMATION) */
|
||||
/* TODO: ExecuteSearch(KESTREL_ACL_FILTER, g_rgszObjectAttrs, KESTREL_OBJECT_ATTR_COUNT, &hSearch) */
|
||||
|
||||
/* TODO: loop: GetNextRow → GetColumn(distinguishedName/objectClass/objectSid/nTSecurityDescriptor)
|
||||
→ ADsOpenObject(DN, IID_IDirectoryObject, &pDirObj)
|
||||
→ KestrelGetObjectSecurityDescriptor
|
||||
→ GetSecurityDescriptorDacl
|
||||
→ KestrelWalkDacl
|
||||
→ pResult->cObjectsScanned++ / cObjectsErrored++ */
|
||||
|
||||
*ppResult = pResult;
|
||||
pResult = NULL; /* ownership transferred */
|
||||
|
||||
Cleanup:
|
||||
if (hSearch && pSearch)
|
||||
IDirectorySearch_CloseSearchHandle(pSearch, hSearch);
|
||||
if (pSearch)
|
||||
IDirectorySearch_Release(pSearch);
|
||||
KestrelFreeExtendedRightsTable(pRights);
|
||||
if (pResult) KestrelFreeACLScanResult(pResult);
|
||||
return hr;
|
||||
}
|
||||
|
||||
/* ─────────────────────────────────────────────────────────────────────────── */
|
||||
/* Internal helper implementations */
|
||||
/* ─────────────────────────────────────────────────────────────────────────── */
|
||||
|
||||
_Must_inspect_result_
|
||||
static HRESULT
|
||||
KestrelACLResultAppend(
|
||||
_Inout_ KESTREL_ACL_SCAN_RESULT* pResult,
|
||||
_In_ const KESTREL_ACL_EDGE* pEdge)
|
||||
{
|
||||
/* Initial allocation: 4096 edges; double on each growth */
|
||||
if (pResult->cEdges == pResult->cCapacity) {
|
||||
DWORD cNew = pResult->cCapacity ? pResult->cCapacity * 2 : 4096;
|
||||
KESTREL_ACL_EDGE* pNew = (KESTREL_ACL_EDGE*)HeapReAlloc(
|
||||
GetProcessHeap(), HEAP_ZERO_MEMORY,
|
||||
pResult->rgEdges,
|
||||
cNew * sizeof(KESTREL_ACL_EDGE));
|
||||
if (!pNew) return E_OUTOFMEMORY;
|
||||
pResult->rgEdges = pNew;
|
||||
pResult->cCapacity = cNew;
|
||||
}
|
||||
|
||||
pResult->rgEdges[pResult->cEdges++] = *pEdge;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static KESTREL_ACL_EDGE_TYPE
|
||||
KestrelClassifyAccessMask(
|
||||
_In_ DWORD dwAccessMask,
|
||||
_In_opt_ GUID* pObjectTypeGuid)
|
||||
{
|
||||
/* Order matters: check broadest rights first */
|
||||
if (dwAccessMask & GENERIC_ALL) return EDGE_GENERIC_ALL;
|
||||
if (dwAccessMask & WRITE_DAC) return EDGE_WRITE_DACL;
|
||||
if (dwAccessMask & WRITE_OWNER) return EDGE_WRITE_OWNER;
|
||||
if (dwAccessMask & GENERIC_WRITE) return EDGE_GENERIC_WRITE;
|
||||
if (dwAccessMask & ADS_RIGHT_DS_CONTROL_ACCESS) return EDGE_EXTENDED_RIGHT;
|
||||
if (dwAccessMask & ADS_RIGHT_DS_WRITE_PROP) return EDGE_WRITE_PROPERTY;
|
||||
if (dwAccessMask & ADS_RIGHT_DS_CREATE_CHILD) return EDGE_CREATE_CHILD;
|
||||
if (dwAccessMask & ADS_RIGHT_DS_DELETE_CHILD) return EDGE_DELETE_CHILD;
|
||||
if (dwAccessMask & ADS_RIGHT_DS_SELF) return EDGE_SELF;
|
||||
return EDGE_UNKNOWN;
|
||||
}
|
||||
|
||||
static VOID
|
||||
KestrelGuidToString(
|
||||
_In_ const GUID* pGuid,
|
||||
_Out_writes_z_(cchBuf) LPWSTR pwszBuf,
|
||||
_In_ SIZE_T cchBuf)
|
||||
{
|
||||
StringCchPrintfW(pwszBuf, cchBuf,
|
||||
L"{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
|
||||
pGuid->Data1, pGuid->Data2, pGuid->Data3,
|
||||
pGuid->Data4[0], pGuid->Data4[1], pGuid->Data4[2], pGuid->Data4[3],
|
||||
pGuid->Data4[4], pGuid->Data4[5], pGuid->Data4[6], pGuid->Data4[7]);
|
||||
}
|
||||
|
||||
VOID
|
||||
KestrelFreeExtendedRightsTable(
|
||||
_In_opt_ _Post_ptr_invalid_ KESTREL_EXTENDED_RIGHT* pRightsHead)
|
||||
{
|
||||
while (pRightsHead) {
|
||||
KESTREL_EXTENDED_RIGHT* pNext = pRightsHead->pNext;
|
||||
if (pRightsHead->rgwszAppliesTo) {
|
||||
for (DWORD i = 0; i < pRightsHead->cAppliesTo; i++)
|
||||
HeapFree(GetProcessHeap(), 0, pRightsHead->rgwszAppliesTo[i]);
|
||||
HeapFree(GetProcessHeap(), 0, pRightsHead->rgwszAppliesTo);
|
||||
}
|
||||
HeapFree(GetProcessHeap(), 0, pRightsHead);
|
||||
pRightsHead = pNext;
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
KestrelFreeACLScanResult(
|
||||
_In_opt_ _Post_ptr_invalid_ KESTREL_ACL_SCAN_RESULT* pResult)
|
||||
{
|
||||
if (!pResult) return;
|
||||
if (pResult->rgEdges)
|
||||
HeapFree(GetProcessHeap(), 0, pResult->rgEdges);
|
||||
HeapFree(GetProcessHeap(), 0, pResult);
|
||||
}
|
||||
Binary file not shown.
Reference in New Issue
Block a user