diff --git a/.github/workflows/native-package.yml b/.github/workflows/native-package.yml deleted file mode 100644 index 5dfbf9f..0000000 --- a/.github/workflows/native-package.yml +++ /dev/null @@ -1,42 +0,0 @@ -name: native package -on: workflow_dispatch -jobs: - build-native: - name: native build - runs-on: windows-2022 - strategy: - fail-fast: false - matrix: - arch: [ x86, x64, arm64 ] - - steps: - - name: Configure runner - run: | - Install-Module -Name VsDevShell -Force - - - name: Check out ${{ github.repository }} - uses: actions/checkout@v3 - - - name: Build Detours (${{matrix.arch}}) - shell: pwsh - run: | - Enter-VsDevShell ${{matrix.arch}} - .\detours.ps1 - - - name: Build MsRdpEx (${{matrix.arch}}) - shell: pwsh - run: | - $ArchDir = "${{matrix.arch}}" - $BuildDir = "build-$ArchDir" - $MsvcArch = @{"x86"="Win32";"x64"="x64";"arm64"="ARM64"}["${{matrix.arch}}"] - cmake -G "Visual Studio 17 2022" -A $MsvcArch -DWITH_DOTNET=OFF -B $BuildDir - cmake --build $BuildDir --config Release - New-Item -ItemType Directory -Path "dependencies/MsRdpEx/$ArchDir" | Out-Null - Copy-Item "$BuildDir/Release/MsRdpEx.dll" "dependencies/MsRdpEx/$ArchDir/MsRdpEx.dll" - Copy-Item "$BuildDir/Release/MsRdpEx_Exe.exe" "dependencies/MsRdpEx/$ArchDir/MsRdpEx.exe" - - - name: Upload MsRdpEx (${{matrix.arch}}) - uses: actions/upload-artifact@v3 - with: - name: MsRdpEx-${{matrix.arch}} - path: dependencies/MsRdpEx/${{matrix.arch}} diff --git a/.github/workflows/nuget-package.yml b/.github/workflows/nuget-package.yml index 99e9948..4692714 100644 --- a/.github/workflows/nuget-package.yml +++ b/.github/workflows/nuget-package.yml @@ -3,8 +3,21 @@ name: nuget package on: workflow_dispatch: inputs: + version: + description: 'release version' + default: "latest" + required: true + detours-git-commit: + description: 'Detours git commit' + default: '4b8c659' + required: true + skip-publish: + description: 'Skip publishing' + required: true + type: boolean + default: false dry-run: - description: 'Dry run' + description: Dry run (simulate) required: true type: boolean default: true @@ -14,28 +27,53 @@ on: jobs: preflight: name: Preflight - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 outputs: - dry-run: ${{ steps.get-dry-run.outputs.dry-run }} + package-env: ${{ steps.info.outputs.package-env }} + package-version: ${{ steps.info.outputs.package-version }} + dry-run: ${{ steps.info.outputs.dry-run }} steps: - - name: Get dry run - id: get-dry-run + - name: Package information + id: info shell: pwsh run: | - Set-PSDebug -Trace 1 - - $IsDryRun = '${{ github.event.inputs.dry-run }}' -Eq 'true' -Or '${{ github.event_name }}' -Eq 'schedule' + $IsMasterBranch = ('${{ github.ref_name }}' -eq 'master') + $DryRun = [System.Boolean]::Parse('${{ inputs.dry-run }}') - if ($IsDryRun) { - echo "dry-run=true" >> $Env:GITHUB_OUTPUT + $PackageEnv = if ($IsMasterBranch) { + "publish-prod" } else { - echo "dry-run=false" >> $Env:GITHUB_OUTPUT + "publish-test" + } + + if (-Not $IsMasterBranch) { + $DryRun = $true # force dry run when not on master branch + } + if ('${{ github.event_name }}' -Eq 'schedule') { + $DryRun = $true # force dry run for scheduled runs + } + + $PackageVersion = '${{ github.event.inputs.version }}' + if ($PackageVersion -eq 'latest') { + $PackageVersion = (Get-Date -Format "yyyy.MM.dd") + ".0" + } + + if ($PackageVersion -NotMatch '^\d+\.\d+\.\d+\.\d+$') { + throw "invalid version format: $PackageVersion, expected: 1.2.3.4" } + echo "package-env=$PackageEnv" >> $Env:GITHUB_OUTPUT + echo "package-version=$PackageVersion" >> $Env:GITHUB_OUTPUT + echo "dry-run=$($DryRun.ToString().ToLower())" >> $Env:GITHUB_OUTPUT + + echo "::notice::Version: $PackageVersion" + echo "::notice::DryRun: $DryRun" + build-native: name: Build native library runs-on: windows-2022 + needs: [preflight] strategy: fail-fast: false matrix: @@ -43,25 +81,47 @@ jobs: steps: - name: Configure runner + shell: pwsh run: | Install-Module -Name VsDevShell -Force - name: Check out ${{ github.repository }} uses: actions/checkout@v3 - - name: Build Detours (${{matrix.arch}}) + - name: Set package version shell: pwsh run: | - Set-PSDebug -Trace 1 + $PackageVersion = '${{ needs.preflight.outputs.package-version }}' + $csprojPath = "dotnet\Devolutions.MsRdpEx\Devolutions.MsRdpEx.csproj" + $csprojContent = Get-Content $csprojPath -Raw + $csprojContent = $csprojContent -Replace '().*?()', "$PackageVersion" + Set-Content -Path $csprojPath -Value $csprojContent -Encoding UTF8 + + - name: Restore Detours Cache (${{matrix.arch}}) + id: cache-detours + uses: actions/cache/restore@v3 + with: + path: dependencies/detours + key: detours-${{ matrix.arch }}-${{ inputs.detours-git-commit }} + - name: Build Detours (${{matrix.arch}}) + if: steps.cache-detours.outputs.cache-hit != 'true' + shell: pwsh + run: | Enter-VsDevShell ${{matrix.arch}} - .\detours.ps1 + $GitCommit = '${{ inputs.detours-git-commit }}' + .\detours.ps1 -GitCommit $GitCommit + + - name: Save Detours Cache (${{matrix.arch}}) + if: steps.cache-detours.outputs.cache-hit != 'true' + uses: actions/cache/save@v3 + with: + path: dependencies/detours + key: detours-${{ matrix.arch }}-${{ inputs.detours-git-commit }} - name: Build MsRdpEx.dll (${{matrix.arch}}) shell: pwsh run: | - Set-PSDebug -Trace 1 - $ArchDir = "${{matrix.arch}}" $BuildDir = "build-$ArchDir" $MsvcArch = @{"x86"="Win32";"x64"="x64";"arm64"="ARM64"}["${{matrix.arch}}"] @@ -69,6 +129,8 @@ jobs: cmake --build $BuildDir --config Release New-Item -ItemType Directory -Path "dependencies/MsRdpEx/$ArchDir" | Out-Null Copy-Item "$BuildDir/Release/MsRdpEx.dll" "dependencies/MsRdpEx/$ArchDir" + Copy-Item "$BuildDir/Release/MsRdpEx.pdb" "dependencies/MsRdpEx/$ArchDir" + Copy-Item "$BuildDir/Release/MsRdpEx_Exe.exe" "dependencies/MsRdpEx/$ArchDir/MsRdpEx.exe" - name: Upload native components uses: actions/upload-artifact@v3 @@ -79,12 +141,21 @@ jobs: build-managed: name: Build and package managed library runs-on: windows-2022 - needs: build-native + needs: [preflight, build-native] steps: - name: Check out ${{ github.repository }} uses: actions/checkout@v3 + - name: Set package version + shell: pwsh + run: | + $PackageVersion = '${{ needs.preflight.outputs.package-version }}' + $csprojPath = "dotnet\Devolutions.MsRdpEx\Devolutions.MsRdpEx.csproj" + $csprojContent = Get-Content $csprojPath -Raw + $csprojContent = $csprojContent -Replace '().*?()', "$PackageVersion" + Set-Content -Path $csprojPath -Value $csprojContent -Encoding UTF8 + - name: Prepare dependencies shell: pwsh run: | @@ -99,7 +170,6 @@ jobs: shell: pwsh run: | Set-PSDebug -Trace 1 - Set-Location "dependencies/MsRdpEx" $(Get-Item ".\MsRdpEx-*") | ForEach-Object { ($p1,$p2) = $_.Name -Split '-'; Rename-Item $_ $p2 } Get-ChildItem * -Recurse @@ -108,7 +178,6 @@ jobs: shell: pwsh run: | Set-PSDebug -Trace 1 - $BuildDir = "build-dotnet" cmake -G "Visual Studio 17 2022" -A x64 -DWITH_DOTNET=ON -DWITH_NATIVE=OFF -B $BuildDir cmake --build $BuildDir --config Release @@ -121,13 +190,11 @@ jobs: path: package/*.nupkg publish: - name: Publish NuGet package - runs-on: ubuntu-20.04 - environment: nuget-publish - if: needs.preflight.outputs.dry-run == 'false' - needs: - - preflight - - build-managed + name: Publish packages + runs-on: ubuntu-22.04 + needs: [preflight, build-native, build-managed] + environment: ${{ needs.preflight.outputs.package-env }} + if: ${{ fromJSON(inputs.skip-publish) == false }} steps: - name: Download NuGet package artifact @@ -139,24 +206,45 @@ jobs: - name: Publish to nuget.org shell: pwsh run: | - Set-PSDebug -Trace 1 + $DryRun = [System.Boolean]::Parse('${{ needs.preflight.outputs.dry-run }}') + $NugetPackage = (Get-Item ./package/*.nupkg) | Resolve-Path -Relative + + $PushArgs = @( + 'nuget', 'push', "$NugetPackage", + '--api-key', '${{ secrets.NUGET_API_KEY }}', + '--source', 'https://api.nuget.org/v3/index.json', + '--skip-duplicate', '--no-symbols' + ) + Write-Host "dotnet $($PushArgs -Join ' ')" + if ($DryRun) { + Write-Host "Dry Run: skipping nuget.org publishing!" + } else { + & 'dotnet' $PushArgs + } + + - name: Create GitHub release + shell: pwsh + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + working-directory: package + run: | + $PackageVersion = '${{ needs.preflight.outputs.package-version }}' + $DryRun = [System.Boolean]::Parse('${{ needs.preflight.outputs.dry-run }}') - $Files = Get-ChildItem -Recurse package/*.nupkg - - foreach ($File in $Files) { - $PushCmd = @( - 'dotnet', - 'nuget', - 'push', - "$File", - '--api-key', - '${{ secrets.NUGET_API_KEY }}', - '--source', - 'https://api.nuget.org/v3/index.json', - '--skip-duplicate' - ) - - Write-Host "Publishing $($File.Name)..." - $PushCmd = $PushCmd -Join ' ' - Invoke-Expression $PushCmd + $HashPath = 'checksums' + $Files = Get-Item * | % { Get-FileHash -Algorithm SHA256 $_.FullName } + $Files | % { "$($_.Hash) $(Split-Path $_.Path -Leaf)" } | Out-File -FilePath $HashPath -Append -Encoding ASCII + + echo "::group::checksums" + Get-Content $HashPath + echo "::endgroup::" + + $ReleaseTag = "v$Version" + $ReleaseTitle = "MsRdpEx v${Version}" + $Repository = $Env:GITHUB_REPOSITORY + + if ($DryRun) { + Write-Host "Dry Run: skipping GitHub release!" + } else { + & gh release create $ReleaseTag --repo $Repository --title $ReleaseTitle ./* } diff --git a/CMakeLists.txt b/CMakeLists.txt index 824e691..8709768 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,7 +29,7 @@ message(STATUS "VERSION: ${MSRDPEX_VERSION}") set(MSRDPEX_NAME "MsRdpEx") set(MSRDPEX_VENDOR "Devolutions Inc.") -set(MSRDPEX_COPYRIGHT "Copyright 2021-2022 ${MSRDPEX_VENDOR}") +set(MSRDPEX_COPYRIGHT "Copyright 2021-2023 ${MSRDPEX_VENDOR}") set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) @@ -44,24 +44,36 @@ if(NOT DEFINED WITH_DOTNET) endif() if(MSVC) - include(MSVCRuntime) + include(MSVCRuntime) - if(NOT DEFINED MSVC_RUNTIME) - set(MSVC_RUNTIME "static") - endif() + if(NOT DEFINED MSVC_RUNTIME) + set(MSVC_RUNTIME "static") + endif() - configure_msvc_runtime() + configure_msvc_runtime() endif() if(WIN32) - set(C_FLAGS "") - set(C_FLAGS "${C_FLAGS} -D_UNICODE") - set(C_FLAGS "${C_FLAGS} -D_CRT_SECURE_NO_WARNINGS") - set(C_FLAGS "${C_FLAGS} -DWIN32_LEAN_AND_MEAN") - set(C_FLAGS "${C_FLAGS} -D_WINSOCK_DEPRECATED_NO_WARNINGS") - set(C_FLAGS "${C_FLAGS} -DWINVER=0x0602 -D_WIN32_WINNT=0x0602") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${C_FLAGS}") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${C_FLAGS}") + set(C_FLAGS "") + set(C_FLAGS "${C_FLAGS} -D_UNICODE") + set(C_FLAGS "${C_FLAGS} -D_CRT_SECURE_NO_WARNINGS") + set(C_FLAGS "${C_FLAGS} -DWIN32_LEAN_AND_MEAN") + set(C_FLAGS "${C_FLAGS} -D_WINSOCK_DEPRECATED_NO_WARNINGS") + set(C_FLAGS "${C_FLAGS} -DWINVER=0x0602 -D_WIN32_WINNT=0x0602") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${C_FLAGS}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${C_FLAGS}") + + set(C_FLAGS_RELEASE "/Zi /GF") # produce debug symbols in release builds + set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${C_FLAGS_RELEASE}") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${C_FLAGS_RELEASE}") + + # http://devcenter.wintellect.com/jrobbins/correctly-creating-native-c-release-build-pdbs + set(LINKER_FLAGS_RELEASE "/DEBUG") + set(LINKER_FLAGS_RELEASE "${LINKER_FLAGS_RELEASE} /OPT:REF /OPT:ICF") + set(LINKER_FLAGS_RELEASE "${LINKER_FLAGS_RELEASE} /MAP /MAPINFO:EXPORTS") + set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${LINKER_FLAGS_RELEASE}" CACHE STRING "" FORCE) + set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} ${LINKER_FLAGS_RELEASE}" CACHE STRING "" FORCE) + set(CMAKE_MODULE_LINKER_FLAGS_RELEASE "${CMAKE_MODULE_LINKER_FLAGS_RELEASE} ${LINKER_FLAGS_RELEASE}" CACHE STRING "" FORCE) endif() set(DEPENDENCIES_DIR "${CMAKE_SOURCE_DIR}/dependencies") diff --git a/detours.ps1 b/detours.ps1 index 1c2ccbe..7182b6a 100644 --- a/detours.ps1 +++ b/detours.ps1 @@ -1,3 +1,7 @@ +param( + [string] $GitRepo = 'https://github.com/microsoft/Detours', + [string] $GitCommit = '4b8c659' # July 24, 2023 +) $RepoRoot = $PSScriptRoot @@ -8,12 +12,12 @@ Push-Location Set-Location $SourcesDir if (-Not (Test-Path -Path "detours")) { - & 'git' 'clone' 'https://github.com/microsoft/Detours' 'detours' + & 'git' 'clone' $GitRepo 'detours' } Set-Location "detours/src" -& 'git' 'checkout' '45a76a3' # August 17, 2021 +& 'git' 'checkout' $GitCommit if (-Not (Test-Path Env:VSCMD_ARG_TGT_ARCH)) { throw "VSCMD_ARG_TGT_ARCH is not set, use a Visual Studio developer shell" diff --git a/dll/ApiHooks.cpp b/dll/ApiHooks.cpp index fa9d5d6..081b834 100644 --- a/dll/ApiHooks.cpp +++ b/dll/ApiHooks.cpp @@ -976,6 +976,12 @@ bool MsRdpEx_IsAddressInModule(PVOID pAddress, LPCTSTR pszModule) return result; } +bool MsRdpEx_IsAddressInRdpAxModule(PVOID pAddress) +{ + return MsRdpEx_IsAddressInModule(pAddress, L"mstscax.dll") || + MsRdpEx_IsAddressInModule(pAddress, L"rdclientax.dll"); +} + void MsRdpEx_GlobalInit() { MsRdpEx_NameResolver_Get(); diff --git a/dll/MsRdpEx.h b/dll/MsRdpEx.h index 8e6fab6..fc2b71c 100644 --- a/dll/MsRdpEx.h +++ b/dll/MsRdpEx.h @@ -205,6 +205,7 @@ LONG MsRdpEx_AttachHooks(); LONG MsRdpEx_DetachHooks(); bool MsRdpEx_IsAddressInModule(PVOID pAddress, LPCTSTR pszModule); +bool MsRdpEx_IsAddressInRdpAxModule(PVOID pAddress); LONG MsRdpEx_GetRectWidth(LPRECT rect); LONG MsRdpEx_GetRectHeight(LPRECT rect); diff --git a/dll/RdpSettings.cpp b/dll/RdpSettings.cpp index 8537721..2e38733 100644 --- a/dll/RdpSettings.cpp +++ b/dll/RdpSettings.cpp @@ -55,7 +55,7 @@ static HRESULT Hook_ITSPropertySet_SetBoolProperty(ITSPropertySet* This, const c return hr; } -static int g_UiShowConnectionInformation = 0; +static int g_InitializeKDCProxyClient = 0; static HRESULT Hook_ITSPropertySet_GetBoolProperty(ITSPropertySet* This, const char* propName, int* propValue) { @@ -68,25 +68,25 @@ static HRESULT Hook_ITSPropertySet_GetBoolProperty(ITSPropertySet* This, const c // CTsConnectionInfoDlg::GetExpandedInfoString crashes if we set TSGTransportIsUsed true when it's not // CTscSslFilter::OnConnected checks IgnoreAuthenticationLevel, NegotiateSecurityLayer right before calling // CTscSslFilter::InitializeKDCProxyClient, so use this to our advantage to filter out undesired call sites. - // We use a basic g_UiShowConnectionInformation state machine, checking for caller DLLs, and hope for the best. - if (MsRdpEx_IsAddressInModule(_ReturnAddress(), L"mstscax.dll") || - MsRdpEx_IsAddressInModule(_ReturnAddress(), L"rdclientax.dll")) { - if (MsRdpEx_StringIEquals(propName, "IgnoreAuthenticationLevel")) { - if (g_UiShowConnectionInformation == 0) { - g_UiShowConnectionInformation = 1; - } + // We use a basic g_InitializeKDCProxyClient state machine, checking for caller DLLs, and hope for the best. + if (MsRdpEx_StringIEquals(propName, "IgnoreAuthenticationLevel") && + MsRdpEx_IsAddressInRdpAxModule(_ReturnAddress())) { + if (g_InitializeKDCProxyClient == 0) { + g_InitializeKDCProxyClient = 1; } - else if (MsRdpEx_StringIEquals(propName, "NegotiateSecurityLayer")) { - if (g_UiShowConnectionInformation == 1) { // - g_UiShowConnectionInformation = 2; - } + } + else if (MsRdpEx_StringIEquals(propName, "NegotiateSecurityLayer") && + MsRdpEx_IsAddressInRdpAxModule(_ReturnAddress())) { + if (g_InitializeKDCProxyClient == 1) { + g_InitializeKDCProxyClient = 2; } - else if (MsRdpEx_StringIEquals(propName, "TSGTransportIsUsed")) { - if (g_UiShowConnectionInformation == 2) { - g_UiShowConnectionInformation = 0; - *propValue = 1; // bypass if (TSGTransportIsUsed) { /* break Kerberos */ } - MsRdpEx_LogPrint(TRACE, "TSGTransportIsUsed is a lie!"); - } + } + else if (MsRdpEx_StringIEquals(propName, "TSGTransportIsUsed") && + MsRdpEx_IsAddressInRdpAxModule(_ReturnAddress())) { + if (g_InitializeKDCProxyClient == 2) { + g_InitializeKDCProxyClient = 0; + *propValue = 1; // bypass if (TSGTransportIsUsed) { /* break Kerberos */ } + MsRdpEx_LogPrint(TRACE, "TSGTransportIsUsed is a lie!"); } } diff --git a/dotnet/Devolutions.MsRdpEx/Devolutions.MsRdpEx.csproj b/dotnet/Devolutions.MsRdpEx/Devolutions.MsRdpEx.csproj index b652876..05b66fa 100644 --- a/dotnet/Devolutions.MsRdpEx/Devolutions.MsRdpEx.csproj +++ b/dotnet/Devolutions.MsRdpEx/Devolutions.MsRdpEx.csproj @@ -3,7 +3,7 @@ Devolutions.MsRdpEx Devolutions.MsRdpEx - 2023.9.28.0 + 1.0.0.0 mamoreau@devolutions.net Devolutions Microsoft RDP Extensions