@@ -29,12 +29,71 @@ 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 = userSettings.BuildFeatureFlags ();
92+ Settings.StorageFlags = storageFlags;
93+ }
94+ };
95+
96+ } // namespace
3897
3998WSLCSessionManagerImpl::~WSLCSessionManagerImpl ()
4099{
@@ -51,22 +110,42 @@ WSLCSessionManagerImpl::~WSLCSessionManagerImpl()
51110
52111void WSLCSessionManagerImpl::CreateSession (const WSLCSessionSettings* Settings, WSLCSessionFlags Flags, IWSLCSession** WslcSession)
53112{
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-
63113 auto tokenInfo = GetCallingProcessTokenInfo ();
114+ const auto callerToken = wsl::windows::common::security::GetUserToken (TokenImpersonation);
115+
116+ // Resolve display name upfront (for both default and custom sessions).
117+ std::wstring resolvedDisplayName;
118+ if (Settings == nullptr )
119+ {
120+ // Default session: name determined from token.
121+ resolvedDisplayName = tokenInfo.Elevated ? wsl::windows::wslc::DefaultAdminSessionName : wsl::windows::wslc::DefaultSessionName;
122+ Flags = WSLCSessionFlagsOpenExisting | WSLCSessionFlagsPersistent;
123+ }
124+ else
125+ {
126+ THROW_HR_IF (E_INVALIDARG, Settings->DisplayName == nullptr || wcslen (Settings->DisplayName ) == 0 );
127+ THROW_HR_IF (E_INVALIDARG, Settings->StoragePath != nullptr && wcslen (Settings->StoragePath ) == 0 );
128+ THROW_HR_IF (E_INVALIDARG, wcslen (Settings->DisplayName ) >= std::size (WSLCSessionInformation{}.DisplayName ));
129+ THROW_HR_IF_MSG (
130+ E_INVALIDARG,
131+ WI_IsAnyFlagSet (Settings->StorageFlags , ~WSLCSessionStorageFlagsValid),
132+ " Invalid storage flags: %i" ,
133+ Settings->StorageFlags );
134+
135+ // Reserved names can only be assigned server-side via null Settings.
136+ THROW_HR_IF (
137+ E_ACCESSDENIED,
138+ wsl::shared::string::IsEqual (Settings->DisplayName , wsl::windows::wslc::DefaultSessionName, true ) ||
139+ wsl::shared::string::IsEqual (Settings->DisplayName , wsl::windows::wslc::DefaultAdminSessionName, true ));
140+
141+ resolvedDisplayName = Settings->DisplayName ;
142+ }
64143
65144 std::lock_guard lock (m_wslcSessionsLock);
66145
67146 // Check for an existing session first.
68147 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 ))
148+ if (!wsl::shared::string::IsEqual (entry.DisplayName .c_str (), resolvedDisplayName. c_str () ))
70149 {
71150 return {};
72151 }
@@ -88,6 +167,14 @@ void WSLCSessionManagerImpl::CreateSession(const WSLCSessionSettings* Settings,
88167
89168 wslutil::StopWatch stopWatch;
90169
170+ // Initialize settings for the default session.
171+ std::unique_ptr<SessionSettings> defaultSettings;
172+ if (Settings == nullptr )
173+ {
174+ defaultSettings = SessionSettings::Default (callerToken.get (), tokenInfo.Elevated );
175+ Settings = &defaultSettings->Settings ;
176+ }
177+
91178 HRESULT creationResult = wil::ResultFromException ([&]() {
92179 // Get caller info.
93180 const auto callerProcess = wslutil::OpenCallingProcess (PROCESS_QUERY_LIMITED_INFORMATION);
@@ -103,13 +190,13 @@ void WSLCSessionManagerImpl::CreateSession(const WSLCSessionSettings* Settings,
103190 AddSessionProcessToJobObject (factory.get ());
104191
105192 // Create the session via the factory.
106- const auto sessionSettings = CreateSessionSettings (sessionId, creatorPid, Settings);
193+ const auto sessionSettings = CreateSessionSettings (sessionId, creatorPid, Settings, resolvedDisplayName. c_str () );
107194 wil::com_ptr<IWSLCSession> session;
108195 wil::com_ptr<IWSLCSessionReference> serviceRef;
109196 THROW_IF_FAILED (factory->CreateSession (&sessionSettings, vm.Get (), &session, &serviceRef));
110197
111198 // 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)});
199+ m_sessions.push_back ({std::move (serviceRef), sessionId, creatorPid, resolvedDisplayName , std::move (tokenInfo)});
113200
114201 // For persistent sessions, also hold a strong reference to keep them alive.
115202 const bool persistent = WI_IsFlagSet (Flags, WSLCSessionFlagsPersistent);
@@ -122,19 +209,18 @@ void WSLCSessionManagerImpl::CreateSession(const WSLCSessionSettings* Settings,
122209 });
123210
124211 // This telemetry event is used to keep track of session creation performance (via CreationTimeMs) and failure reasons (via Result).
125-
126212 WSL_LOG_TELEMETRY (
127213 " WSLCCreateSession" ,
128214 PDT_ProductAndServicePerformance,
129215 TraceLoggingKeyword (MICROSOFT_KEYWORD_CRITICAL_DATA),
130- TraceLoggingValue (Settings-> DisplayName , " Name" ),
216+ TraceLoggingValue (resolvedDisplayName. c_str () , " Name" ),
131217 TraceLoggingValue (stopWatch.ElapsedMilliseconds (), " CreationTimeMs" ),
132218 TraceLoggingValue (creationResult, " Result" ),
133219 TraceLoggingValue (tokenInfo.Elevated , " Elevated" ),
134220 TraceLoggingValue (static_cast <uint32_t >(Flags), " Flags" ),
135221 TraceLoggingLevel (WINEVENT_LEVEL_INFO));
136222
137- THROW_IF_FAILED_MSG (creationResult, " Failed to create session: %ls" , Settings-> DisplayName );
223+ THROW_IF_FAILED_MSG (creationResult, " Failed to create session: %ls" , resolvedDisplayName. c_str () );
138224}
139225
140226void WSLCSessionManagerImpl::OpenSession (ULONG Id, IWSLCSession** Session)
@@ -160,6 +246,14 @@ void WSLCSessionManagerImpl::OpenSessionByName(LPCWSTR DisplayName, IWSLCSession
160246{
161247 auto tokenInfo = GetCallingProcessTokenInfo ();
162248
249+ // Null name = default session, resolved from caller's token.
250+ std::wstring resolvedName;
251+ if (DisplayName == nullptr )
252+ {
253+ resolvedName = tokenInfo.Elevated ? wsl::windows::wslc::DefaultAdminSessionName : wsl::windows::wslc::DefaultSessionName;
254+ DisplayName = resolvedName.c_str ();
255+ }
256+
163257 auto result = ForEachSession<HRESULT>([&](auto & entry, const wil::com_ptr<IWSLCSession>& session) noexcept -> std::optional<HRESULT> {
164258 if (!wsl::shared::string::IsEqual (entry.DisplayName .c_str (), DisplayName))
165259 {
@@ -207,12 +301,23 @@ void WSLCSessionManagerImpl::GetVersion(_Out_ WSLCVersion* Version)
207301 Version->Revision = WSL_PACKAGE_VERSION_REVISION;
208302}
209303
210- WSLCSessionInitSettings WSLCSessionManagerImpl::CreateSessionSettings (_In_ ULONG SessionId, _In_ DWORD CreatorPid, _In_ const WSLCSessionSettings* Settings)
304+ void WSLCSessionManagerImpl::EnterSession (_In_ LPCWSTR DisplayName, _In_ LPCWSTR StoragePath, IWSLCSession** WslcSession)
305+ {
306+ THROW_HR_IF (E_POINTER, DisplayName == nullptr || StoragePath == nullptr );
307+ THROW_HR_IF (E_INVALIDARG, DisplayName[0 ] == L' \0 ' || StoragePath[0 ] == L' \0 ' );
308+
309+ const auto callerToken = wsl::windows::common::security::GetUserToken (TokenImpersonation);
310+ auto sessionSettings = SessionSettings::Custom (callerToken.get (), DisplayName, StoragePath, WSLCSessionStorageFlagsNoCreate);
311+ CreateSession (&sessionSettings.Settings , WSLCSessionFlagsNone, WslcSession);
312+ }
313+
314+ WSLCSessionInitSettings WSLCSessionManagerImpl::CreateSessionSettings (
315+ _In_ ULONG SessionId, _In_ DWORD CreatorPid, _In_ const WSLCSessionSettings* Settings, _In_ LPCWSTR ResolvedDisplayName)
211316{
212317 WSLCSessionInitSettings sessionSettings{};
213318 sessionSettings.SessionId = SessionId;
214319 sessionSettings.CreatorPid = CreatorPid;
215- sessionSettings.DisplayName = Settings-> DisplayName ;
320+ sessionSettings.DisplayName = ResolvedDisplayName ;
216321 sessionSettings.StoragePath = Settings->StoragePath ;
217322 sessionSettings.MaximumStorageSizeMb = Settings->MaximumStorageSizeMb ;
218323 sessionSettings.BootTimeoutMs = Settings->BootTimeoutMs ;
@@ -292,6 +397,11 @@ HRESULT WSLCSessionManager::CreateSession(const WSLCSessionSettings* WslcSession
292397 return CallImpl (&WSLCSessionManagerImpl::CreateSession, WslcSessionSettings, Flags, WslcSession);
293398}
294399
400+ HRESULT WSLCSessionManager::EnterSession (_In_ LPCWSTR DisplayName, _In_ LPCWSTR StoragePath, IWSLCSession** WslcSession)
401+ {
402+ return CallImpl (&WSLCSessionManagerImpl::EnterSession, DisplayName, StoragePath, WslcSession);
403+ }
404+
295405HRESULT WSLCSessionManager::ListSessions (_Out_ WSLCSessionInformation** Sessions, _Out_ ULONG* SessionsCount)
296406{
297407 return CallImpl (&WSLCSessionManagerImpl::ListSessions, Sessions, SessionsCount);
0 commit comments