Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .qubesbuilder
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ vm:
- vs2022/core-agent-windows.sln
bin:
- vs2022/x64/@CONFIGURATION@/advertise-tools/advertise-tools.exe
- vs2022/x64/@CONFIGURATION@/autologon/autologon.exe
- vs2022/x64/@CONFIGURATION@/clipboard-copy/clipboard-copy.exe
- vs2022/x64/@CONFIGURATION@/clipboard-paste/clipboard-paste.exe
- vs2022/x64/@CONFIGURATION@/file-receiver/file-receiver.exe
Expand Down
206 changes: 206 additions & 0 deletions src/autologon/autologon.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
/*
* The Qubes OS Project, http://www.qubes-os.org
*
* Copyright (c) 2025 Rafa� Wojdy�a <omeg@invisiblethingslab.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

#include <assert.h>
#include <stdio.h>

// needed to avoid NTSTATUS related redefinitions
#define WIN32_NO_STATUS
#include <Windows.h>
#undef WIN32_NO_STATUS

#include <LMaccess.h>
#include <ntstatus.h>
#include <winternl.h>
#include <WtsApi32.h>

// this needs to be last, otherwise we get some more redefinitions...
#define _NTDEF_
#include <NTSecAPI.h>

#include "log.h"

// Set current user's password to a random one and enable automatic logon.
// The password is stored as a LSA secret (not plaintext in the registry).
// NOTE: Changing the password invalidates all credentials stored by the system on behalf of the user.
// All user files with NTFS encryption will become inaccessible!
// TODO: support Active Directory

// generate random password
// length is in characters, including NULL terminator
static DWORD GenerateRandomPassword(_Out_writes_z_(length) wchar_t* password, _In_ size_t length)
{
if (length < 1)
return ERROR_INVALID_PARAMETER;

const wchar_t* chars =
L"abcdefghijklmnopqrstuvwxyz"
L"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
L"0123456789"
L"`~!@#$%^&*()-_=+[]{};':\",.<>/?\\|";
size_t chars_count = wcslen(chars);
assert(chars_count < 255);

for (size_t i = 0; i < length - 1; i++)
{
BYTE idx;
NTSTATUS status = BCryptGenRandom(
NULL, // algorithm provider
&idx, // buffer
sizeof(idx), // buffer size
BCRYPT_USE_SYSTEM_PREFERRED_RNG); // flags

if (!NT_SUCCESS(status))
return win_perror2(RtlNtStatusToDosError(status), "BCryptGenRandom");

// this doesn't generate a perfect uniform distribution, but is good enough for our purpose
password[i] = chars[idx % chars_count];
}
password[length - 1] = L'\0';

return ERROR_SUCCESS;
}

// set password for a user account
DWORD SetUserPassword(_In_z_ const wchar_t* username, _In_z_ wchar_t* password)
{
USER_INFO_1003 pwd_info;
pwd_info.usri1003_password = password;

LogInfo("Setting password for user '%s'", username);
DWORD status = NetUserSetInfo(
NULL, // server name
username, // user name
1003, // info id (password)
(BYTE*)&pwd_info, // data
NULL); // parameter error index

if (status != ERROR_SUCCESS)
return win_perror2(status, "NetUserSetInfo(password)");
return ERROR_SUCCESS;
}

// enable autologon and set DefaultUserName
DWORD SetAutologonRegistry(_In_z_ const wchar_t* username)
{
HKEY key;
DWORD status = RegOpenKeyExW(
HKEY_LOCAL_MACHINE, // parent
L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon", // path
0, // options
KEY_READ | KEY_WRITE, // access
&key);

if (status != ERROR_SUCCESS)
return win_perror2(status, "RegOpenKeyExW(Winlogon)");

status = RegSetValueExW(
key, // parent
L"AutoAdminLogon", // name
0, // reserved
REG_SZ, // type
(BYTE*)L"1", // value
4); // size

if (status != ERROR_SUCCESS)
return win_perror2(status, "RegSetValueEx(AutoAdminLogon)");

status = RegSetValueExW(
key, // parent
L"DefaultUserName", // name
0, // reserved
REG_SZ, // type
(BYTE*)username, // value
2 * (DWORD)(wcslen(username) + 1)); // size

if (status != ERROR_SUCCESS)
return win_perror2(status, "RegSetValueEx(DefaultUserName)");

return ERROR_SUCCESS;
}

// set DefaultPassword for autologon as a LSA secret
DWORD SetAutologonPassword(_In_z_ wchar_t* password)
{
LSA_OBJECT_ATTRIBUTES attrs;
ZeroMemory(&attrs, sizeof(attrs));

LSA_HANDLE lsa;
NTSTATUS status = LsaOpenPolicy(
NULL, // server
&attrs, // attributes
POLICY_CREATE_SECRET, // access
&lsa); // output

if (!NT_SUCCESS(status))
return win_perror2(LsaNtStatusToWinError(status), "LsaOpenPolicy");

LSA_UNICODE_STRING secret_name;
RtlInitUnicodeString(&secret_name, L"DefaultPassword");

LSA_UNICODE_STRING secret_data;
RtlInitUnicodeString(&secret_data, password);

status = LsaStorePrivateData(lsa, &secret_name, &secret_data);
status = LsaNtStatusToWinError(status);

if (status != ERROR_SUCCESS)
return win_perror2(status, "LsaStorePrivateData");

return ERROR_SUCCESS;
}

int main(void)
{
wchar_t* username;
DWORD un_size;
if (!WTSQuerySessionInformationW(
WTS_CURRENT_SERVER_HANDLE, // server
WTS_CURRENT_SESSION, // session id
WTSUserName, // info type
&username, // buffer ptr
&un_size)) // returned size

return win_perror("WTSQuerySessionInformationW");

LogDebug("active user name: %s", username);

wchar_t password[LM20_PWLEN];
DWORD status = GenerateRandomPassword(password, ARRAYSIZE(password));
if (status != ERROR_SUCCESS)
return status;

status = SetUserPassword(username, password);
if (status != ERROR_SUCCESS)
return status;

status = SetAutologonRegistry(username);
if (status != ERROR_SUCCESS)
return status;

status = SetAutologonPassword(password);
if (status != ERROR_SUCCESS)
return status;

SecureZeroMemory(password, sizeof(password));

WTSFreeMemory(username);
return status;
}
3 changes: 3 additions & 0 deletions src/autologon/version.rc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#define QWT_FILEDESCRIPTION_STR "Qubes autologon"

#include "..\version_common.rc"
102 changes: 102 additions & 0 deletions vs2022/autologon/autologon.vcxproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\src\autologon\autologon.c" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\src\autologon\version.rc" />
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{c051fd1a-1daa-437a-94c5-622566761d86}</ProjectGuid>
<RootNamespace>autologon</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings" />
<ImportGroup Label="Shared" />
<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" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);$(QUBES_INCLUDES);$(QUBES_REPO)\vmm-xen-windows-pvdrivers\inc;$(QUBES_REPO)\core-vchan-xen\inc;$(QUBES_REPO)\windows-utils\inc;$(QUBES_REPO)\core-qubesdb\inc</IncludePath>
<LibraryPath>$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(QUBES_LIBS);$(QUBES_REPO)\vmm-xen-windows-pvdrivers\lib;$(QUBES_REPO)\core-vchan-xen\lib;$(QUBES_REPO)\windows-utils\lib;$(QUBES_REPO)\core-qubesdb\lib</LibraryPath>
<LinkIncremental>false</LinkIncremental>
<IntDir>$(ProjectDir)\..\tmp\$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
<OutDir>$(ProjectDir)\..\$(Platform)\$(Configuration)\$(ProjectName)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);$(QUBES_INCLUDES);$(QUBES_REPO)\vmm-xen-windows-pvdrivers\inc;$(QUBES_REPO)\core-vchan-xen\inc;$(QUBES_REPO)\windows-utils\inc;$(QUBES_REPO)\core-qubesdb\inc</IncludePath>
<LibraryPath>$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(QUBES_LIBS);$(QUBES_REPO)\vmm-xen-windows-pvdrivers\lib;$(QUBES_REPO)\core-vchan-xen\lib;$(QUBES_REPO)\windows-utils\lib;$(QUBES_REPO)\core-qubesdb\lib</LibraryPath>
<LinkIncremental>false</LinkIncremental>
<IntDir>$(ProjectDir)\..\tmp\$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
<OutDir>$(ProjectDir)\..\$(Platform)\$(Configuration)\$(ProjectName)\</OutDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<TreatWarningAsError>true</TreatWarningAsError>
<LanguageStandard_C>stdc17</LanguageStandard_C>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>$(CoreLibraryDependencies);%(AdditionalDependencies);bcrypt.lib;netapi32.lib;ntdll.lib;wtsapi32.lib;windows-utils.lib</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<TreatWarningAsError>true</TreatWarningAsError>
<LanguageStandard_C>stdc17</LanguageStandard_C>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>$(CoreLibraryDependencies);%(AdditionalDependencies);bcrypt.lib;netapi32.lib;ntdll.lib;wtsapi32.lib;windows-utils.lib</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
9 changes: 9 additions & 0 deletions vs2022/autologon/autologon.vcxproj.filters
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="..\..\src\autologon\autologon.c" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\src\autologon\version.rc" />
</ItemGroup>
</Project>
10 changes: 10 additions & 0 deletions vs2022/core-agent-windows.sln
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wait-for-logon", "qubes-rpc
{9556A5D1-B82A-47BC-8050-A116EE418530} = {9556A5D1-B82A-47BC-8050-A116EE418530}
{AC3F4370-1B6A-4F11-8860-D932ECBDEED9} = {AC3F4370-1B6A-4F11-8860-D932ECBDEED9}
{AD828571-1DD7-45FD-B5C2-907DE485F39B} = {AD828571-1DD7-45FD-B5C2-907DE485F39B}
{C051FD1A-1DAA-437A-94C5-622566761D86} = {C051FD1A-1DAA-437A-94C5-622566761D86}
{C5293A35-58E1-4BCB-8BC7-8D0BE9503D97} = {C5293A35-58E1-4BCB-8BC7-8D0BE9503D97}
{CCBBEACD-F536-41E4-A10F-87E6271723E0} = {CCBBEACD-F536-41E4-A10F-87E6271723E0}
{DBA888E0-F486-41C5-AF4D-B4FD04330082} = {DBA888E0-F486-41C5-AF4D-B4FD04330082}
Expand All @@ -96,6 +97,11 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wait-for-logon", "qubes-rpc
{FA1DE025-C52D-4088-A52C-4E298B445256} = {FA1DE025-C52D-4088-A52C-4E298B445256}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "autologon", "autologon\autologon.vcxproj", "{C051FD1A-1DAA-437A-94C5-622566761D86}"
ProjectSection(ProjectDependencies) = postProject
{C5293A35-58E1-4BCB-8BC7-8D0BE9503D97} = {C5293A35-58E1-4BCB-8BC7-8D0BE9503D97}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Expand Down Expand Up @@ -166,6 +172,10 @@ Global
{AF84F8F2-E5B4-41DD-BED5-5B19D96F0A02}.Debug|x64.Build.0 = Debug|x64
{AF84F8F2-E5B4-41DD-BED5-5B19D96F0A02}.Release|x64.ActiveCfg = Release|x64
{AF84F8F2-E5B4-41DD-BED5-5B19D96F0A02}.Release|x64.Build.0 = Release|x64
{C051FD1A-1DAA-437A-94C5-622566761D86}.Debug|x64.ActiveCfg = Debug|x64
{C051FD1A-1DAA-437A-94C5-622566761D86}.Debug|x64.Build.0 = Debug|x64
{C051FD1A-1DAA-437A-94C5-622566761D86}.Release|x64.ActiveCfg = Release|x64
{C051FD1A-1DAA-437A-94C5-622566761D86}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down