Skip to content

Commit 3a2f1ec

Browse files
authored
Merge pull request #397 from mjcheetham/chmod
Create plaintext credential store directory with safer permissions
2 parents 91e4a84 + 97ab665 commit 3a2f1ec

File tree

3 files changed

+95
-0
lines changed

3 files changed

+95
-0
lines changed

docs/linuxcredstores.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,10 @@ the environment variable `GCM_PLAINTEXT_STORE_PATH` environment variable.
134134

135135
If the directory does not exist is will be created.
136136

137+
On POSIX platforms the newly created store directory will have permissions set
138+
such that only the owner can `r`ead/`w`rite/e`x`ecute (`700` or `drwx---`).
139+
Permissions on existing directories will not be modified.
140+
137141
---
138142

139143
<p align="center">
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT license.
3+
using System;
4+
using System.Runtime.InteropServices;
5+
6+
namespace Microsoft.Git.CredentialManager.Interop.Posix.Native
7+
{
8+
public static class Stat
9+
{
10+
[DllImport("libc", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
11+
public static extern int chmod(string path, NativeFileMode mode);
12+
}
13+
[Flags]
14+
public enum NativeFileMode
15+
{
16+
NONE = 0,
17+
18+
// Default permissions (RW for owner, RW for group, RW for other)
19+
DEFAULT = S_IWOTH | S_IROTH | S_IWGRP | S_IRGRP | S_IWUSR | S_IRUSR,
20+
21+
// All file access permissions (RWX for owner, group, and other)
22+
ACCESSPERMS = S_IRWXO | S_IRWXU | S_IRWXG,
23+
24+
// Read for owner (0000400)
25+
S_IRUSR = 0x100,
26+
// Write for owner (0000200)
27+
S_IWUSR = 0x080,
28+
// Execute for owner (0000100)
29+
S_IXUSR = 0x040,
30+
// Access permissions for owner
31+
S_IRWXU = S_IRUSR | S_IWUSR | S_IXUSR,
32+
33+
// Read for group (0000040)
34+
S_IRGRP = 0x020,
35+
// Write for group (0000020)
36+
S_IWGRP = 0x010,
37+
// Execute for group (0000010)
38+
S_IXGRP = 0x008,
39+
// Access permissions for group
40+
S_IRWXG = S_IRGRP | S_IWGRP | S_IXGRP,
41+
42+
// Read for other (0000004)
43+
S_IROTH = 0x004,
44+
// Write for other (0000002)
45+
S_IWOTH = 0x002,
46+
// Execute for other (0000001)
47+
S_IXOTH = 0x001,
48+
// Access permissions for other
49+
S_IRWXO = S_IROTH | S_IWOTH | S_IXOTH,
50+
51+
// Set user ID on execution (0004000)
52+
S_ISUID = 0x800,
53+
// Set group ID on execution (0002000)
54+
S_ISGID = 0x400,
55+
// Sticky bit (0001000)
56+
S_ISVTX = 0x200,
57+
}
58+
}

src/shared/Microsoft.Git.CredentialManager/PlaintextCredentialStore.cs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ public ICredential Get(string service, string account)
5959

6060
public void AddOrUpdate(string service, string account, string secret)
6161
{
62+
// Ensure the store root exists and permissions are set
63+
EnsureStoreRoot();
64+
6265
string serviceSlug = CreateServiceSlug(service);
6366
string servicePath = Path.Combine(StoreRoot, serviceSlug);
6467

@@ -161,6 +164,36 @@ protected virtual void SerializeCredential(FileCredential credential)
161164
}
162165
}
163166

167+
/// <summary>
168+
/// Ensure the store root directory exists. If it does not, create a new directory with
169+
/// permissions that only permit the owner to read/write/execute. Permissions on an existing
170+
/// directory are not modified.
171+
/// </summary>
172+
private void EnsureStoreRoot()
173+
{
174+
if (FileSystem.DirectoryExists(StoreRoot))
175+
{
176+
// Don't touch the permissions on the existing directory
177+
return;
178+
}
179+
180+
FileSystem.CreateDirectory(StoreRoot);
181+
182+
// We only set file system permissions on POSIX platforms
183+
if (!PlatformUtils.IsPosix())
184+
{
185+
return;
186+
}
187+
188+
// Set store root permissions such that only the owner can read/write/execute
189+
var mode = Interop.Posix.Native.NativeFileMode.S_IRUSR |
190+
Interop.Posix.Native.NativeFileMode.S_IWUSR |
191+
Interop.Posix.Native.NativeFileMode.S_IXUSR;
192+
193+
// Ignore the return code.. this is a best effort only
194+
Interop.Posix.Native.Stat.chmod(StoreRoot, mode);
195+
}
196+
164197
private string CreateServiceSlug(string service)
165198
{
166199
var sb = new StringBuilder();

0 commit comments

Comments
 (0)