Skip to content

Commit 4e23d28

Browse files
committed
Fix ownership when cloning elevated
On Windows, if the current user is elevated then any directories created will be owned by the Administrators group. This can cause problems later on in non-elevated contexts due to git's "dubious ownership" check. Git for Windows does not currently 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, the GVFS service which automounts repositories runs under the SYSTEM account, which would still fail the check even if that fix were in place. This commit changes the ownership of the .git directory and the working directory to the current user when cloning.
1 parent 3790eb0 commit 4e23d28

File tree

5 files changed

+46
-1
lines changed

5 files changed

+46
-1
lines changed

GVFS/GVFS.Common/FileSystem/IPlatformFileSystem.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,6 @@ public interface IPlatformFileSystem
1818
bool TryCreateDirectoryWithAdminAndUserModifyPermissions(string directoryPath, out string error);
1919
bool TryCreateOrUpdateDirectoryToAdminModifyPermissions(ITracer tracer, string directoryPath, out string error);
2020
bool IsFileSystemSupported(string path, out string error);
21+
void EnsureDirectoryIsOwnedByCurrentUser(string workingDirectoryRoot);
2122
}
2223
}

GVFS/GVFS.Common/GVFSEnlistment.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ public bool TryCreateEnlistmentSubFolders()
217217
{
218218
try
219219
{
220-
Directory.CreateDirectory(this.WorkingDirectoryRoot);
220+
GVFSPlatform.Instance.FileSystem.EnsureDirectoryIsOwnedByCurrentUser(this.WorkingDirectoryRoot);
221221
this.CreateHiddenDirectory(this.DotGVFSRoot);
222222
}
223223
catch (IOException)

GVFS/GVFS.Platform.Windows/WindowsFileSystem.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,34 @@ public bool IsFileSystemSupported(string path, out string error)
272272
return true;
273273
}
274274

275+
/// <summary>
276+
/// On Windows, if the current user is elevated, the owner of the directory will be the Administrators group by default.
277+
/// This runs afoul of the git "dubious ownership" check, which can fail if either the .git directory or the working directory
278+
/// are not owned by the current user.
279+
///
280+
/// 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,
281+
/// though a fix is in progress in the microsoft fork of git. Libgit2(sharp) also does not have this fix.
282+
///
283+
/// Also, even if the fix were in place, automount would still fail because it runs under SYSTEM account.
284+
///
285+
/// This method ensures that the directory is owned by the current user (which is verified to work for SYSTEM account for automount).
286+
/// </summary>
287+
public void EnsureDirectoryIsOwnedByCurrentUser(string directoryPath)
288+
{
289+
// Ensure directory exists, inheriting all other ACLS
290+
Directory.CreateDirectory(directoryPath);
291+
// If the user is currently elevated, the owner of the directory will be the Administrators group.
292+
DirectorySecurity directorySecurity = Directory.GetAccessControl(directoryPath);
293+
IdentityReference directoryOwner = directorySecurity.GetOwner(typeof(SecurityIdentifier));
294+
SecurityIdentifier administratorsSid = new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null);
295+
if (directoryOwner == administratorsSid)
296+
{
297+
WindowsIdentity currentUser = WindowsIdentity.GetCurrent();
298+
directorySecurity.SetOwner(currentUser.User);
299+
Directory.SetAccessControl(directoryPath, directorySecurity);
300+
}
301+
}
302+
275303
private class NativeFileReader
276304
{
277305
private const uint GenericRead = 0x80000000;

GVFS/GVFS.UnitTests/Mock/FileSystem/MockPlatformFileSystem.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,5 +70,10 @@ public bool IsFileSystemSupported(string path, out string error)
7070
error = null;
7171
return true;
7272
}
73+
74+
public void EnsureDirectoryIsOwnedByCurrentUser(string workingDirectoryRoot)
75+
{
76+
throw new NotSupportedException();
77+
}
7378
}
7479
}

GVFS/GVFS/CommandLine/CloneVerb.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -716,6 +716,17 @@ private Result TryInitRepo(ITracer tracer, GitRefs refs, Enlistment enlistmentTo
716716
return new Result(error);
717717
}
718718

719+
try
720+
{
721+
GVFSPlatform.Instance.FileSystem.EnsureDirectoryIsOwnedByCurrentUser(enlistmentToInit.DotGitRoot);
722+
}
723+
catch (IOException e)
724+
{
725+
string error = string.Format("Could not ensure .git directory is owned by current user: {0}", e.Message);
726+
tracer.RelatedError(error);
727+
return new Result(error);
728+
}
729+
719730
GitProcess.Result remoteAddResult = new GitProcess(enlistmentToInit).RemoteAdd("origin", enlistmentToInit.RepoUrl);
720731
if (remoteAddResult.ExitCodeIsFailure)
721732
{

0 commit comments

Comments
 (0)