@@ -29,12 +29,73 @@ Module Name:
2929
3030#include " WSLCSessionManager.h"
3131#include " HcsVirtualMachine.h"
32+ #include " WSLCUserSettings.h"
33+ #include " WSLCSessionDefaults.h"
3234#include " wslutil.h"
35+ #include " filesystem.hpp"
3336
3437using wsl::windows::service::wslc::CallingProcessTokenInfo;
3538using wsl::windows::service::wslc::HcsVirtualMachine;
3639using wsl::windows::service::wslc::WSLCSessionManagerImpl;
3740namespace wslutil = wsl::windows::common::wslutil;
41+ namespace settings = wsl::windows::wslc::settings;
42+
43+ namespace {
44+
45+ // Session settings built server-side from the caller's settings.yaml.
46+ struct SessionSettings
47+ {
48+ std::wstring DisplayName;
49+ std::wstring StoragePath;
50+ WSLCSessionSettings Settings{};
51+
52+ NON_COPYABLE (SessionSettings);
53+ NON_MOVABLE (SessionSettings);
54+
55+ // Default session: name and storage path determined from caller's token.
56+ static std::unique_ptr<SessionSettings> Default (HANDLE UserToken, bool Elevated)
57+ {
58+ auto localAppData = wsl::windows::common::filesystem::GetLocalAppDataPath (UserToken);
59+ settings::UserSettings userSettings (localAppData / L" wslc" );
60+
61+ std::wstring name = Elevated ? wsl::windows::wslc::DefaultAdminSessionName : wsl::windows::wslc::DefaultSessionName;
62+
63+ auto customPath = userSettings.Get <settings::Setting::SessionStoragePath>();
64+ std::filesystem::path basePath =
65+ customPath.empty () ? (localAppData / wsl::windows::wslc::DefaultStorageSubPath) : std::filesystem::path{customPath};
66+ auto storagePath = (basePath / name).wstring ();
67+
68+ return std::unique_ptr<SessionSettings>(
69+ new SessionSettings (std::move (name), std::move (storagePath), WSLCSessionStorageFlagsNone, userSettings));
70+ }
71+
72+ // Custom session: caller provides name and storage path.
73+ static SessionSettings Custom (HANDLE UserToken, LPCWSTR Name, LPCWSTR Path, WSLCSessionStorageFlags StorageFlags = WSLCSessionStorageFlagsNone)
74+ {
75+ auto localAppData = wsl::windows::common::filesystem::GetLocalAppDataPath (UserToken);
76+ settings::UserSettings userSettings (localAppData / L" wslc" );
77+ return SessionSettings (Name, Path, StorageFlags, userSettings);
78+ }
79+
80+ private:
81+ SessionSettings (std::wstring name, std::wstring path, WSLCSessionStorageFlags storageFlags, const settings::UserSettings& userSettings) :
82+ DisplayName (std::move(name)), StoragePath(std::move(path))
83+ {
84+ Settings.DisplayName = DisplayName.c_str ();
85+ Settings.StoragePath = StoragePath.c_str ();
86+ Settings.CpuCount = userSettings.Get <settings::Setting::SessionCpuCount>();
87+ Settings.MemoryMb = userSettings.Get <settings::Setting::SessionMemoryMb>();
88+ Settings.MaximumStorageSizeMb = userSettings.Get <settings::Setting::SessionStorageSizeMb>();
89+ Settings.BootTimeoutMs = wsl::windows::wslc::DefaultBootTimeoutMs;
90+ Settings.NetworkingMode = userSettings.Get <settings::Setting::SessionNetworkingMode>();
91+ Settings.FeatureFlags = WslcFeatureFlagsNone;
92+ WI_SetFlagIf (Settings.FeatureFlags , WslcFeatureFlagsDnsTunneling, userSettings.Get <settings::Setting::SessionDnsTunneling>());
93+ WI_SetFlagIf (Settings.FeatureFlags , WslcFeatureFlagsVirtioFs, userSettings.Get <settings::Setting::SessionHostFileShareMode>() == HostFileShareMode::VirtioFs);
94+ Settings.StorageFlags = storageFlags;
95+ }
96+ };
97+
98+ } // namespace
3899
39100WSLCSessionManagerImpl::~WSLCSessionManagerImpl ()
40101{
@@ -51,22 +112,42 @@ WSLCSessionManagerImpl::~WSLCSessionManagerImpl()
51112
52113void WSLCSessionManagerImpl::CreateSession (const WSLCSessionSettings* Settings, WSLCSessionFlags Flags, IWSLCSession** WslcSession)
53114{
54- // Ensure that the session display name is non-null and not too long.
55- THROW_HR_IF (E_INVALIDARG, Settings->DisplayName == nullptr );
56- THROW_HR_IF (E_INVALIDARG, wcslen (Settings->DisplayName ) >= std::size (WSLCSessionInformation{}.DisplayName ));
57- THROW_HR_IF_MSG (
58- E_INVALIDARG,
59- WI_IsAnyFlagSet (Settings->StorageFlags , ~WSLCSessionStorageFlagsValid),
60- " Invalid storage flags: %i" ,
61- Settings->StorageFlags );
62-
63115 auto tokenInfo = GetCallingProcessTokenInfo ();
116+ const auto callerToken = wsl::windows::common::security::GetUserToken (TokenImpersonation);
117+
118+ // Resolve display name upfront (for both default and custom sessions).
119+ std::wstring resolvedDisplayName;
120+ if (Settings == nullptr )
121+ {
122+ // Default session: name determined from token.
123+ resolvedDisplayName = tokenInfo.Elevated ? wsl::windows::wslc::DefaultAdminSessionName : wsl::windows::wslc::DefaultSessionName;
124+ Flags = WSLCSessionFlagsOpenExisting | WSLCSessionFlagsPersistent;
125+ }
126+ else
127+ {
128+ THROW_HR_IF (E_INVALIDARG, Settings->DisplayName == nullptr || wcslen (Settings->DisplayName ) == 0 );
129+ THROW_HR_IF (E_INVALIDARG, Settings->StoragePath != nullptr && wcslen (Settings->StoragePath ) == 0 );
130+ THROW_HR_IF (E_INVALIDARG, wcslen (Settings->DisplayName ) >= std::size (WSLCSessionInformation{}.DisplayName ));
131+ THROW_HR_IF_MSG (
132+ E_INVALIDARG,
133+ WI_IsAnyFlagSet (Settings->StorageFlags , ~WSLCSessionStorageFlagsValid),
134+ " Invalid storage flags: %i" ,
135+ Settings->StorageFlags );
136+
137+ // Reserved names can only be assigned server-side via null Settings.
138+ THROW_HR_IF (
139+ E_ACCESSDENIED,
140+ wsl::shared::string::IsEqual (Settings->DisplayName , wsl::windows::wslc::DefaultSessionName, true ) ||
141+ wsl::shared::string::IsEqual (Settings->DisplayName , wsl::windows::wslc::DefaultAdminSessionName, true ));
142+
143+ resolvedDisplayName = Settings->DisplayName ;
144+ }
64145
65146 std::lock_guard lock (m_wslcSessionsLock);
66147
67148 // Check for an existing session first.
68149 auto result = ForEachSession<HRESULT>([&](auto & entry, const wil::com_ptr<IWSLCSession>& session) noexcept -> std::optional<HRESULT> {
69- if (!wsl::shared::string::IsEqual (entry.DisplayName .c_str (), Settings-> DisplayName ))
150+ if (!wsl::shared::string::IsEqual (entry.DisplayName .c_str (), resolvedDisplayName. c_str () ))
70151 {
71152 return {};
72153 }
@@ -88,6 +169,14 @@ void WSLCSessionManagerImpl::CreateSession(const WSLCSessionSettings* Settings,
88169
89170 wslutil::StopWatch stopWatch;
90171
172+ // Initialize settings for the default session.
173+ std::unique_ptr<SessionSettings> defaultSettings;
174+ if (Settings == nullptr )
175+ {
176+ defaultSettings = SessionSettings::Default (callerToken.get (), tokenInfo.Elevated );
177+ Settings = &defaultSettings->Settings ;
178+ }
179+
91180 HRESULT creationResult = wil::ResultFromException ([&]() {
92181 // Get caller info.
93182 const auto callerProcess = wslutil::OpenCallingProcess (PROCESS_QUERY_LIMITED_INFORMATION);
@@ -103,13 +192,13 @@ void WSLCSessionManagerImpl::CreateSession(const WSLCSessionSettings* Settings,
103192 AddSessionProcessToJobObject (factory.get ());
104193
105194 // Create the session via the factory.
106- const auto sessionSettings = CreateSessionSettings (sessionId, creatorPid, Settings);
195+ const auto sessionSettings = CreateSessionSettings (sessionId, creatorPid, Settings, resolvedDisplayName. c_str () );
107196 wil::com_ptr<IWSLCSession> session;
108197 wil::com_ptr<IWSLCSessionReference> serviceRef;
109198 THROW_IF_FAILED (factory->CreateSession (&sessionSettings, vm.Get (), &session, &serviceRef));
110199
111200 // Track the session via its service ref, along with metadata and security info.
112- m_sessions.push_back ({std::move (serviceRef), sessionId, creatorPid, Settings-> DisplayName , std::move (tokenInfo)});
201+ m_sessions.push_back ({std::move (serviceRef), sessionId, creatorPid, resolvedDisplayName , std::move (tokenInfo)});
113202
114203 // For persistent sessions, also hold a strong reference to keep them alive.
115204 const bool persistent = WI_IsFlagSet (Flags, WSLCSessionFlagsPersistent);
@@ -122,19 +211,18 @@ void WSLCSessionManagerImpl::CreateSession(const WSLCSessionSettings* Settings,
122211 });
123212
124213 // This telemetry event is used to keep track of session creation performance (via CreationTimeMs) and failure reasons (via Result).
125-
126214 WSL_LOG_TELEMETRY (
127215 " WSLCCreateSession" ,
128216 PDT_ProductAndServicePerformance,
129217 TraceLoggingKeyword (MICROSOFT_KEYWORD_CRITICAL_DATA),
130- TraceLoggingValue (Settings-> DisplayName , " Name" ),
218+ TraceLoggingValue (resolvedDisplayName. c_str () , " Name" ),
131219 TraceLoggingValue (stopWatch.ElapsedMilliseconds (), " CreationTimeMs" ),
132220 TraceLoggingValue (creationResult, " Result" ),
133221 TraceLoggingValue (tokenInfo.Elevated , " Elevated" ),
134222 TraceLoggingValue (static_cast <uint32_t >(Flags), " Flags" ),
135223 TraceLoggingLevel (WINEVENT_LEVEL_INFO));
136224
137- THROW_IF_FAILED_MSG (creationResult, " Failed to create session: %ls" , Settings-> DisplayName );
225+ THROW_IF_FAILED_MSG (creationResult, " Failed to create session: %ls" , resolvedDisplayName. c_str () );
138226}
139227
140228void WSLCSessionManagerImpl::OpenSession (ULONG Id, IWSLCSession** Session)
@@ -160,6 +248,14 @@ void WSLCSessionManagerImpl::OpenSessionByName(LPCWSTR DisplayName, IWSLCSession
160248{
161249 auto tokenInfo = GetCallingProcessTokenInfo ();
162250
251+ // Null name = default session, resolved from caller's token.
252+ std::wstring resolvedName;
253+ if (DisplayName == nullptr )
254+ {
255+ resolvedName = tokenInfo.Elevated ? wsl::windows::wslc::DefaultAdminSessionName : wsl::windows::wslc::DefaultSessionName;
256+ DisplayName = resolvedName.c_str ();
257+ }
258+
163259 auto result = ForEachSession<HRESULT>([&](auto & entry, const wil::com_ptr<IWSLCSession>& session) noexcept -> std::optional<HRESULT> {
164260 if (!wsl::shared::string::IsEqual (entry.DisplayName .c_str (), DisplayName))
165261 {
@@ -207,12 +303,23 @@ void WSLCSessionManagerImpl::GetVersion(_Out_ WSLCVersion* Version)
207303 Version->Revision = WSL_PACKAGE_VERSION_REVISION;
208304}
209305
210- WSLCSessionInitSettings WSLCSessionManagerImpl::CreateSessionSettings (_In_ ULONG SessionId, _In_ DWORD CreatorPid, _In_ const WSLCSessionSettings* Settings)
306+ void WSLCSessionManagerImpl::EnterSession (_In_ LPCWSTR DisplayName, _In_ LPCWSTR StoragePath, IWSLCSession** WslcSession)
307+ {
308+ THROW_HR_IF (E_POINTER, DisplayName == nullptr || StoragePath == nullptr );
309+ THROW_HR_IF (E_INVALIDARG, DisplayName[0 ] == L' \0 ' || StoragePath[0 ] == L' \0 ' );
310+
311+ const auto callerToken = wsl::windows::common::security::GetUserToken (TokenImpersonation);
312+ auto sessionSettings = SessionSettings::Custom (callerToken.get (), DisplayName, StoragePath, WSLCSessionStorageFlagsNoCreate);
313+ CreateSession (&sessionSettings.Settings , WSLCSessionFlagsNone, WslcSession);
314+ }
315+
316+ WSLCSessionInitSettings WSLCSessionManagerImpl::CreateSessionSettings (
317+ _In_ ULONG SessionId, _In_ DWORD CreatorPid, _In_ const WSLCSessionSettings* Settings, _In_ LPCWSTR ResolvedDisplayName)
211318{
212319 WSLCSessionInitSettings sessionSettings{};
213320 sessionSettings.SessionId = SessionId;
214321 sessionSettings.CreatorPid = CreatorPid;
215- sessionSettings.DisplayName = Settings-> DisplayName ;
322+ sessionSettings.DisplayName = ResolvedDisplayName ;
216323 sessionSettings.StoragePath = Settings->StoragePath ;
217324 sessionSettings.MaximumStorageSizeMb = Settings->MaximumStorageSizeMb ;
218325 sessionSettings.BootTimeoutMs = Settings->BootTimeoutMs ;
@@ -292,6 +399,11 @@ HRESULT WSLCSessionManager::CreateSession(const WSLCSessionSettings* WslcSession
292399 return CallImpl (&WSLCSessionManagerImpl::CreateSession, WslcSessionSettings, Flags, WslcSession);
293400}
294401
402+ HRESULT WSLCSessionManager::EnterSession (_In_ LPCWSTR DisplayName, _In_ LPCWSTR StoragePath, IWSLCSession** WslcSession)
403+ {
404+ return CallImpl (&WSLCSessionManagerImpl::EnterSession, DisplayName, StoragePath, WslcSession);
405+ }
406+
295407HRESULT WSLCSessionManager::ListSessions (_Out_ WSLCSessionInformation** Sessions, _Out_ ULONG* SessionsCount)
296408{
297409 return CallImpl (&WSLCSessionManagerImpl::ListSessions, Sessions, SessionsCount);
0 commit comments