Skip to content

Commit b123cde

Browse files
committed
Fix short notation paths being unauthorized [VPNWIN-2627]
1 parent a0012c2 commit b123cde

File tree

6 files changed

+43
-34
lines changed

6 files changed

+43
-34
lines changed

src/IssueReporting/ProtonVPN.IssueReporting/SentryInitializer.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
using System.Collections.Generic;
2121
using System.Diagnostics;
22+
using System.Linq;
2223
using System.Reflection;
2324
using System.Text;
2425
using ProtonVPN.Builds.Variables;
@@ -113,7 +114,7 @@ private static void LogSentryEvent(SentryEvent e)
113114

114115
private static string GetLogs()
115116
{
116-
IList<string> logs = _logger?.GetRecentLogs() ?? new List<string>();
117+
IList<string> logs = _logger?.GetRecentLogs().Reverse().ToList() ?? [];
117118
StringBuilder sb = new();
118119
foreach (string log in logs)
119120
{

src/Logging/ProtonVPN.Logging/Log4Net/Log4NetLogger.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ namespace ProtonVPN.Logging.Log4Net
2626
{
2727
public class Log4NetLogger : Log4NetLoggerInitializer, ILogger
2828
{
29+
private const int MAX_RECENT_LOG_LINES = 100;
30+
2931
private readonly IList<string> _recentLogs = new List<string>();
3032

3133
public Log4NetLogger(ILoggerConfiguration loggerConfiguration)
@@ -150,7 +152,7 @@ private void AddMessageToRecentLogs(string message, Exception exception = null,
150152
}
151153
_recentLogs.Add(message);
152154

153-
while (_recentLogs.Count > 100)
155+
while (_recentLogs.Count > MAX_RECENT_LOG_LINES)
154156
{
155157
_recentLogs.RemoveAt(0);
156158
}

src/OperatingSystems/Processes/ProtonVPN.OperatingSystems.Processes.Contracts/IPipeStreamProcessIdentifier.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,6 @@ namespace ProtonVPN.OperatingSystems.Processes.Contracts;
2323

2424
public interface IPipeStreamProcessIdentifier
2525
{
26-
string? GetClientProcessFileName(PipeStream pipeStream);
27-
string? GetServerProcessFileName(PipeStream pipeStream);
26+
string? GetClientProcessFullFilePath(PipeStream pipeStream);
27+
string? GetServerProcessFullFilePath(PipeStream pipeStream);
2828
}

src/OperatingSystems/Processes/ProtonVPN.OperatingSystems.Processes/PipeStreamProcessIdentifier.cs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,18 +35,19 @@ public PipeStreamProcessIdentifier(ILogger logger)
3535
_logger = logger;
3636
}
3737

38-
public string? GetClientProcessFileName(PipeStream pipeStream)
38+
public string? GetClientProcessFullFilePath(PipeStream pipeStream)
3939
{
40-
return GetProcessFileName(GetClientProcessId, pipeStream);
40+
return GetProcessFullFilePath(GetClientProcessId, pipeStream);
4141
}
4242

43-
private string? GetProcessFileName(Func<PipeStream, int> processIdRequester, PipeStream pipeStream)
43+
private string? GetProcessFullFilePath(Func<PipeStream, int> processIdRequester, PipeStream pipeStream)
4444
{
4545
try
4646
{
4747
int processId = processIdRequester(pipeStream);
4848
Process? process = processId == 0 ? null : Process.GetProcessById(processId);
49-
return process?.MainModule?.FileName;
49+
string? filePath = process?.MainModule?.FileName;
50+
return string.IsNullOrWhiteSpace(filePath) ? null : Path.GetFullPath(filePath);
5051
}
5152
catch (Exception ex)
5253
{
@@ -68,9 +69,9 @@ private int GetClientProcessId(PipeStream pipeStream)
6869
[return: MarshalAs(UnmanagedType.Bool)]
6970
private static extern bool GetNamedPipeClientProcessId(IntPtr hNamedPipe, out uint clientProcessId);
7071

71-
public string? GetServerProcessFileName(PipeStream pipeStream)
72+
public string? GetServerProcessFullFilePath(PipeStream pipeStream)
7273
{
73-
return GetProcessFileName(GetServerProcessId, pipeStream);
74+
return GetProcessFullFilePath(GetServerProcessId, pipeStream);
7475
}
7576

7677
private int GetServerProcessId(PipeStream pipeStream)

src/ProcessCommunication/Client/ProtonVPN.ProcessCommunication.Client/ResponseHandler.cs

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -72,33 +72,36 @@ private async Task HandleResponseAsync(HttpResponseMessage response)
7272
string serviceProcessVersion = GetHeaderValue(response.Headers, HttpConfiguration.SERVICE_PROCESS_VERSION);
7373
string installedServiceVersion = GetHeaderValue(response.Headers, HttpConfiguration.INSTALLED_SERVICE_VERSION);
7474

75-
_logger.Error<ProcessCommunicationErrorLog>(
76-
$"Received HTTP status code {response.StatusCode} from gRPC server. " +
77-
$"Client Process Path: '{clientProcessPath}' Version '{clientProcessVersion}'), " +
78-
$"Service Process Path: '{serviceProcessPath}' Version '{serviceProcessVersion}'), " +
79-
$"Installed Service Path: '{installedServicePath}' Version '{installedServiceVersion}')");
75+
_logger.Error<ProcessCommunicationErrorLog>($"Received HTTP status code {response.StatusCode} from gRPC server. " +
76+
$"Client Process Path: '{clientProcessPath}' Version '{clientProcessVersion}', " +
77+
$"Service Process Path: '{serviceProcessPath}' Version '{serviceProcessVersion}', " +
78+
$"Installed Service Path: '{installedServicePath}' Version '{installedServiceVersion}'");
8079

8180
if (response.StatusCode == HttpStatusCode.Unauthorized)
8281
{
83-
await Handle401UnauthorizedAsync(clientProcessVersion, serviceProcessVersion);
82+
string logMessageDetails =
83+
$"Client Process Path: '{clientProcessPath}', " +
84+
$"Service Process Path: '{serviceProcessPath}', " +
85+
$"Installed Service Path: '{installedServicePath}'";
86+
await Handle401UnauthorizedAsync(clientProcessVersion, serviceProcessVersion, logMessageDetails);
8487
}
8588
}
8689
}
8790

88-
private async Task Handle401UnauthorizedAsync(string clientProcessVersion, string serviceProcessVersion)
91+
private async Task Handle401UnauthorizedAsync(string clientProcessVersion, string serviceProcessVersion, string logMessageDetails)
8992
{
9093
await _semaphore.WaitAsync();
9194
try
9295
{
93-
Handle401Unauthorized(clientProcessVersion, serviceProcessVersion);
96+
Handle401Unauthorized(clientProcessVersion, serviceProcessVersion, logMessageDetails);
9497
}
9598
finally
9699
{
97100
_semaphore.Release();
98101
}
99102
}
100103

101-
private void Handle401Unauthorized(string clientProcessVersionString, string serviceProcessVersionString)
104+
private void Handle401Unauthorized(string clientProcessVersionString, string serviceProcessVersionString, string logMessageDetails)
102105
{
103106
string versions = $"ClientProcessVersion: {clientProcessVersionString}, ServiceProcessVersion: {serviceProcessVersionString}";
104107

@@ -116,7 +119,7 @@ private void Handle401Unauthorized(string clientProcessVersionString, string ser
116119

117120
if (!_is401UnauthorizedWithoutBeingBelowServiceVersionHandled)
118121
{
119-
_issueReporter.CaptureMessage(logExplanation, versions);
122+
_issueReporter.CaptureMessage(logExplanation, logMessageDetails);
120123
_is401UnauthorizedWithoutBeingBelowServiceVersionHandled = true;
121124
}
122125
}

src/ProcessCommunication/Server/ProtonVPN.ProcessCommunication.Server/NamedPipeAuthorizationMiddleware.cs

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ public async Task InvokeAsync(HttpContext context)
7979
{
8080
context.Response.StatusCode = authorizationResult.StatusCode;
8181

82-
string installedServicePath = _registryEditor.ReadString(_registryUri);
82+
string installedServicePath = Path.GetFullPath(_registryEditor.ReadString(_registryUri));
8383

8484
string clientProcessVersionString = GetVersionFromFilePath(authorizationResult.ClientProcessFileName);
8585
string serviceProcessVersionString = GetVersionFromFilePath(authorizationResult.ServerProcessFileName);
@@ -91,17 +91,17 @@ public async Task InvokeAsync(HttpContext context)
9191
Version.TryParse(installedServiceVersionString, out Version installedServiceVersion) &&
9292
installedServiceVersion > serviceProcessVersion)
9393
{
94-
string serviceStopDescription = $"Client Process Path: '{authorizationResult.ClientProcessFileName}' Version '{clientProcessVersionString}'), " +
95-
$"Service Process Path: '{authorizationResult.ServerProcessFileName}' Version '{serviceProcessVersionString}'), " +
96-
$"Installed Service Path: '{installedServicePath}' Version '{installedServiceVersionString}')";
94+
string serviceStopDescription = $"Client Process Path: '{authorizationResult.ClientProcessFileName}' Version '{clientProcessVersionString}', " +
95+
$"Service Process Path: '{authorizationResult.ServerProcessFileName}' Version '{serviceProcessVersionString}', " +
96+
$"Installed Service Path: '{installedServicePath}' Version '{installedServiceVersionString}'";
9797
await StopServiceAsync(serviceStopDescription);
9898
context.Response.StatusCode = StatusCodes.Status409Conflict;
9999
}
100100

101101
_logger.Error<ProcessCommunicationErrorLog>($"Sending HTTP status code {context.Response.StatusCode} to gRPC client. " +
102-
$"Client Process Path: '{authorizationResult.ClientProcessFileName}' Version '{clientProcessVersionString}'), " +
103-
$"Service Process Path: '{authorizationResult.ServerProcessFileName}' Version '{serviceProcessVersionString}'), " +
104-
$"Installed Service Path: '{installedServicePath}' Version '{installedServiceVersionString}')");
102+
$"Client Process Path: '{authorizationResult.ClientProcessFileName}' Version '{clientProcessVersionString}', " +
103+
$"Service Process Path: '{authorizationResult.ServerProcessFileName}' Version '{serviceProcessVersionString}', " +
104+
$"Installed Service Path: '{installedServicePath}' Version '{installedServiceVersionString}'");
105105

106106
context.Response.Headers[HttpConfiguration.CLIENT_PROCESS_PATH] = authorizationResult.ClientProcessFileName;
107107
context.Response.Headers[HttpConfiguration.SERVICE_PROCESS_PATH] = authorizationResult.ServerProcessFileName;
@@ -160,23 +160,25 @@ private async Task<AuthorizationResult> AuthorizeAsync(HttpContext context)
160160
{
161161
NamedPipeServerStream namedPipe = GetNamedPipe(context);
162162

163-
string clientProcessFileName = _pipeStreamProcessIdentifier.GetClientProcessFileName(namedPipe) ?? string.Empty;
164-
string serverProcessFileName = _pipeStreamProcessIdentifier.GetServerProcessFileName(namedPipe) ?? string.Empty;
163+
string clientProcessPath = _pipeStreamProcessIdentifier.GetClientProcessFullFilePath(namedPipe) ?? string.Empty;
164+
string serverProcessPath = _pipeStreamProcessIdentifier.GetServerProcessFullFilePath(namedPipe) ?? string.Empty;
165165

166-
if (!_config.ServiceExePath.Equals(serverProcessFileName, StringComparison.InvariantCultureIgnoreCase))
166+
string expectedServiceProcessPath = Path.GetFullPath(_config.ServiceExePath);
167+
if (!expectedServiceProcessPath.Equals(serverProcessPath, StringComparison.InvariantCultureIgnoreCase))
167168
{
168169
_logger.Warn<ProcessCommunicationErrorLog>($"The owner of the Named Pipe is not this Service. Dispose and recreate.");
169170
await _recreateAndStartAsyncFunc();
170-
return AuthorizationResult.Error(StatusCodes.Status409Conflict, clientProcessFileName, serverProcessFileName);
171+
return AuthorizationResult.Error(StatusCodes.Status409Conflict, clientProcessPath, serverProcessPath);
171172
}
172173

173-
if (_config.AppExePath.Equals(clientProcessFileName, StringComparison.InvariantCultureIgnoreCase))
174+
string expectedClientProcessPath = Path.GetFullPath(_config.AppExePath);
175+
if (expectedClientProcessPath.Equals(clientProcessPath, StringComparison.InvariantCultureIgnoreCase))
174176
{
175177
return AuthorizationResult.Ok();
176178
}
177179

178-
_logger.Warn<ProcessCommunicationErrorLog>($"The connected client is unauthorized. Client path: '{clientProcessFileName}'. Expected: '{_config.AppExePath}'.");
179-
return AuthorizationResult.Error(StatusCodes.Status401Unauthorized, clientProcessFileName, serverProcessFileName);
180+
_logger.Warn<ProcessCommunicationErrorLog>($"The connected client is unauthorized. Client path: '{clientProcessPath}'. Expected: '{expectedClientProcessPath}'.");
181+
return AuthorizationResult.Error(StatusCodes.Status401Unauthorized, clientProcessPath, serverProcessPath);
180182
}
181183
catch (Exception ex)
182184
{

0 commit comments

Comments
 (0)