Skip to content

[Release] Milestone M253 #1831

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Feb 13, 2025
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 GVFS/GVFS.Common/FileSystem/IPlatformFileSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@ public interface IPlatformFileSystem
bool TryCreateDirectoryWithAdminAndUserModifyPermissions(string directoryPath, out string error);
bool TryCreateOrUpdateDirectoryToAdminModifyPermissions(ITracer tracer, string directoryPath, out string error);
bool IsFileSystemSupported(string path, out string error);
void EnsureDirectoryIsOwnedByCurrentUser(string workingDirectoryRoot);
}
}
2 changes: 1 addition & 1 deletion GVFS/GVFS.Common/GVFSEnlistment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ public bool TryCreateEnlistmentSubFolders()
{
try
{
Directory.CreateDirectory(this.WorkingDirectoryRoot);
GVFSPlatform.Instance.FileSystem.EnsureDirectoryIsOwnedByCurrentUser(this.WorkingDirectoryRoot);
this.CreateHiddenDirectory(this.DotGVFSRoot);
}
catch (IOException)
Expand Down
2 changes: 0 additions & 2 deletions GVFS/GVFS.Common/GVFSPlatform.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,6 @@ public static void Register(GVFSPlatform platform)
public abstract bool TryGetGVFSHooksVersion(out string hooksVersion, out string error);
public abstract bool TryInstallGitCommandHooks(GVFSContext context, string executingDirectory, string hookName, string commandHookPath, out string errorMessage);

public abstract bool TryVerifyAuthenticodeSignature(string path, out string subject, out string issuer, out string error);

public abstract Dictionary<string, string> GetPhysicalDiskInfo(string path, bool sizeStatsOnly);

public abstract bool IsConsoleOutputRedirectedToFile();
Expand Down
1 change: 0 additions & 1 deletion GVFS/GVFS.Platform.Windows/GVFS.Platform.Windows.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
<PackageReference Include="Microsoft.Database.Collections.Generic" Version="1.9.4" />
<PackageReference Include="Microsoft.Database.Isam" Version="1.9.4" />
<PackageReference Include="Microsoft.Windows.ProjFS" Version="1.1.19156.1" />
<PackageReference Include="System.Management.Automation.dll" Version="10.0.10586.0" />
</ItemGroup>

<ItemGroup>
Expand Down
28 changes: 28 additions & 0 deletions GVFS/GVFS.Platform.Windows/WindowsFileSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,34 @@ public bool IsFileSystemSupported(string path, out string error)
return true;
}

/// <summary>
/// On Windows, if the current user is elevated, the owner of the directory will be the Administrators group by default.
/// This runs afoul of the git "dubious ownership" check, which can fail if either the .git directory or the working directory
/// are not owned by the current user.
///
/// At the moment git for windows does not consider a non-elevated admin to be the owner of a directory owned by the Administrators group,
/// though a fix is in progress in the microsoft fork of git. Libgit2(sharp) also does not have this fix.
///
/// Also, even if the fix were in place, automount would still fail because it runs under SYSTEM account.
///
/// This method ensures that the directory is owned by the current user (which is verified to work for SYSTEM account for automount).
/// </summary>
public void EnsureDirectoryIsOwnedByCurrentUser(string directoryPath)
{
// Ensure directory exists, inheriting all other ACLS
Directory.CreateDirectory(directoryPath);
// If the user is currently elevated, the owner of the directory will be the Administrators group.
DirectorySecurity directorySecurity = Directory.GetAccessControl(directoryPath);
IdentityReference directoryOwner = directorySecurity.GetOwner(typeof(SecurityIdentifier));
SecurityIdentifier administratorsSid = new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null);
if (directoryOwner == administratorsSid)
{
WindowsIdentity currentUser = WindowsIdentity.GetCurrent();
directorySecurity.SetOwner(currentUser.User);
Directory.SetAccessControl(directoryPath, directorySecurity);
}
}

private class NativeFileReader
{
private const uint GenericRead = 0x80000000;
Expand Down
25 changes: 0 additions & 25 deletions GVFS/GVFS.Platform.Windows/WindowsPlatform.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
using System.IO;
using System.IO.Pipes;
using System.Linq;
using System.Management.Automation;
using System.Security.AccessControl;
using System.Security.Principal;
using System.ServiceProcess;
Expand Down Expand Up @@ -294,30 +293,6 @@ public override bool TryInstallGitCommandHooks(GVFSContext context, string execu
return true;
}

public override bool TryVerifyAuthenticodeSignature(string path, out string subject, out string issuer, out string error)
{
using (PowerShell powershell = PowerShell.Create())
{
powershell.AddScript($"Get-AuthenticodeSignature -FilePath {path}");

Collection<PSObject> results = powershell.Invoke();
if (powershell.HadErrors || results.Count <= 0)
{
subject = null;
issuer = null;
error = $"Powershell Get-AuthenticodeSignature failed, could not verify authenticode for {path}.";
return false;
}

Signature signature = results[0].BaseObject as Signature;
bool isValid = signature.Status == SignatureStatus.Valid;
subject = signature.SignerCertificate.SubjectName.Name;
issuer = signature.SignerCertificate.IssuerName.Name;
error = isValid == false ? signature.StatusMessage : null;
return isValid;
}
}

public override string GetCurrentUser()
{
WindowsIdentity identity = WindowsIdentity.GetCurrent();
Expand Down
5 changes: 0 additions & 5 deletions GVFS/GVFS.UnitTests/Mock/Common/MockPlatform.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,6 @@ public override bool TryInstallGitCommandHooks(GVFSContext context, string execu
throw new NotSupportedException();
}

public override bool TryVerifyAuthenticodeSignature(string path, out string subject, out string issuer, out string error)
{
throw new NotImplementedException();
}

public override string GetNamedPipeName(string enlistmentRoot)
{
return "GVFS_Mock_PipeName";
Expand Down
5 changes: 5 additions & 0 deletions GVFS/GVFS.UnitTests/Mock/FileSystem/MockPlatformFileSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,5 +70,10 @@ public bool IsFileSystemSupported(string path, out string error)
error = null;
return true;
}

public void EnsureDirectoryIsOwnedByCurrentUser(string workingDirectoryRoot)
{
throw new NotSupportedException();
}
}
}
11 changes: 11 additions & 0 deletions GVFS/GVFS/CommandLine/CloneVerb.cs
Original file line number Diff line number Diff line change
Expand Up @@ -716,6 +716,17 @@ private Result TryInitRepo(ITracer tracer, GitRefs refs, Enlistment enlistmentTo
return new Result(error);
}

try
{
GVFSPlatform.Instance.FileSystem.EnsureDirectoryIsOwnedByCurrentUser(enlistmentToInit.DotGitRoot);
}
catch (IOException e)
{
string error = string.Format("Could not ensure .git directory is owned by current user: {0}", e.Message);
tracer.RelatedError(error);
return new Result(error);
}

GitProcess.Result remoteAddResult = new GitProcess(enlistmentToInit).RemoteAdd("origin", enlistmentToInit.RepoUrl);
if (remoteAddResult.ExitCodeIsFailure)
{
Expand Down