Skip to content

Commit b159fe4

Browse files
committed
Init
1 parent aa05b1a commit b159fe4

18 files changed

+462
-341
lines changed
+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Copyright (c) 2024 Files Community
2+
// Licensed under the MIT License. See the LICENSE.
3+
4+
using Windows.Win32.Foundation;
5+
6+
namespace Files.App.Data.Contracts
7+
{
8+
/// <summary>
9+
/// Provides service to manage storage security objects on NTFS and ReFS.
10+
/// </summary>
11+
public interface IStorageSecurityService
12+
{
13+
/// <summary>
14+
/// Get the owner of the object specified by the path.
15+
/// </summary>
16+
/// <param name="path">The file full path</param>
17+
/// <returns>The SID string of the owner</returns>
18+
string GetOwner(string path);
19+
20+
/// <summary>
21+
/// Set the owner of the object specified by the path.
22+
/// </summary>
23+
/// <param name="path">The file full path</param>
24+
/// <param name="sid">The owner security identifier (SID)</param>
25+
/// <returns></returns>
26+
bool SetOwner(string path, string sid);
27+
28+
/// <summary>
29+
/// Get information about an access control list (ACL).
30+
/// </summary>
31+
/// <param name="path"></param>
32+
/// <param name="isFolder"></param>
33+
/// <returns>If the function succeeds, an instance of AccessControlList; otherwise, null. To get extended error information, call GetLastError.</returns>
34+
WIN32_ERROR GetAcl(string path, bool isFolder, out AccessControlList acl);
35+
36+
/// <summary>
37+
/// Add an default Access Control Entry (ACE) to the specified object's DACL
38+
/// </summary>
39+
/// <param name="path">The object's path to add an new ACE to its DACL</param>
40+
/// <param name="sid">Principal's SID</param>
41+
/// <returns> If the function succeeds, the return value is ERROR_SUCCESS. If the function fails, the return value is a nonzero error code defined in WinError.h.</returns>
42+
WIN32_ERROR AddAce(string szPath, bool isFolder, string szSid);
43+
44+
/// <summary>
45+
/// Add an Access Control Entry (ACE) from the specified object's DACL
46+
/// </summary>
47+
/// <param name="szPath">The object's path to remove an ACE from its DACL</param>
48+
/// <param name="dwAceIndex"></param>
49+
/// <returns></returns>
50+
WIN32_ERROR DeleteAce(string szPath, uint dwAceIndex);
51+
}
52+
}

Diff for: src/Files.App/Utils/Storage/Security/AccessControlEntryFlags.cs renamed to src/Files.App/Data/Enums/AccessControlEntryFlags.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright (c) 2024 Files Community
22
// Licensed under the MIT License. See the LICENSE.
33

4-
namespace Files.App.Utils.Storage
4+
namespace Files.App.Data.Enums
55
{
66
/// <summary>
77
/// Represents inheritance flags of an ACE

Diff for: src/Files.App/Utils/Storage/Security/AccessControlEntryType.cs renamed to src/Files.App/Data/Enums/AccessControlEntryType.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright (c) 2024 Files Community
22
// Licensed under the MIT License. See the LICENSE.
33

4-
namespace Files.App.Utils.Storage
4+
namespace Files.App.Data.Enums
55
{
66
/// <summary>
77
/// Represents ACE type.

Diff for: src/Files.App/Utils/Storage/Security/PrincipalType.cs renamed to src/Files.App/Data/Enums/AccessControlPrincipalType.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
// Copyright (c) 2024 Files Community
22
// Licensed under the MIT License. See the LICENSE.
33

4-
namespace Files.App.Utils.Storage
4+
namespace Files.App.Data.Enums
55
{
66
/// <summary>
77
/// Represents an ACL owner or an ACE principal type
88
/// </summary>
9-
public enum PrincipalType
9+
public enum AccessControlPrincipalType
1010
{
1111
/// <summary>
12-
/// Unknwon principal type
12+
/// Unknown principal type
1313
/// </summary>
1414
Unknown,
1515

Diff for: src/Files.App/Utils/Storage/Security/AccessMaskFlags.cs renamed to src/Files.App/Data/Enums/AccessMaskFlags.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright (c) 2024 Files Community
22
// Licensed under the MIT License. See the LICENSE.
33

4-
namespace Files.App.Utils.Storage
4+
namespace Files.App.Data.Enums
55
{
66
/// <summary>
77
/// Represents access mask flags of an ACE.

Diff for: src/Files.App/Utils/Storage/Security/AccessControlEntry.cs renamed to src/Files.App/Data/Items/AccessControlEntry.cs

+30-11
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright (c) 2024 Files Community
22
// Licensed under the MIT License. See the LICENSE.
33

4-
namespace Files.App.Utils.Storage
4+
namespace Files.App.Data.Items
55
{
66
/// <summary>
77
/// Represents an access control entry (ACE).
@@ -17,7 +17,7 @@ public sealed class AccessControlEntry : ObservableObject
1717
/// The owner in the security descriptor (SD).
1818
/// NULL if the security descriptor has no owner SID.
1919
/// </summary>
20-
public Principal Principal { get; set; }
20+
public AccessControlPrincipal Principal { get; set; }
2121

2222
/// <summary>
2323
/// Whether the ACE is inherited or not
@@ -336,16 +336,16 @@ public AccessControlEntry(bool isFolder, string ownerSid, AccessControlEntryType
336336
{
337337
AccessMaskItems = SecurityAdvancedAccessControlItemFactory.Initialize(this, AreAdvancedPermissionsShown, IsInherited, IsFolder);
338338

339-
//ChangeAccessControlTypeCommand = new RelayCommand<string>(x =>
340-
//{
341-
// AccessControlType = Enum.Parse<AccessControlType>(x);
342-
//});
339+
ChangeAccessControlTypeCommand = new RelayCommand<string>(x =>
340+
{
341+
//AccessControlType = Enum.Parse<AccessControlType>(x);
342+
});
343343

344-
//ChangeInheritanceFlagsCommand = new RelayCommand<string>(x =>
345-
//{
346-
// var parts = x.Split(',');
347-
// InheritanceFlags = Enum.Parse<AccessControlEntryFlags>(parts[0]);
348-
//});
344+
ChangeInheritanceFlagsCommand = new RelayCommand<string>(x =>
345+
{
346+
//var parts = x.Split(',');
347+
//InheritanceFlags = Enum.Parse<AccessControlEntryFlags>(parts[0]);
348+
});
349349

350350
IsFolder = isFolder;
351351
Principal = new(ownerSid);
@@ -402,5 +402,24 @@ private void ToggleDenyAccess(AccessMaskFlags accessMask, bool value)
402402
DeniedAccessMaskFlags &= ~accessMask;
403403
}
404404
}
405+
406+
/// <summary>
407+
/// Gets access control list (ACL) initialized with default data.
408+
/// </summary>
409+
/// <param name="isFolder"></param>
410+
/// <param name="ownerSid"></param>
411+
/// <returns>If the function succeeds, an instance of AccessControlList; otherwise, null.</returns>
412+
public static AccessControlEntry GetDefault(bool isFolder, string ownerSid)
413+
{
414+
return new(
415+
isFolder,
416+
ownerSid,
417+
AccessControlEntryType.Allow,
418+
AccessMaskFlags.ReadAndExecute,
419+
false,
420+
isFolder
421+
? AccessControlEntryFlags.ContainerInherit | AccessControlEntryFlags.ObjectInherit
422+
: AccessControlEntryFlags.None);
423+
}
405424
}
406425
}

Diff for: src/Files.App/Utils/Storage/Security/AccessControlList.cs renamed to src/Files.App/Data/Items/AccessControlList.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright (c) 2024 Files Community
22
// Licensed under the MIT License. See the LICENSE.
33

4-
namespace Files.App.Utils.Storage
4+
namespace Files.App.Data.Items
55
{
66
/// <summary>
77
/// Represents an access control list (ACL).
@@ -22,7 +22,7 @@ public sealed class AccessControlList : ObservableObject
2222
/// The owner in the security descriptor (SD).
2323
/// NULL if the security descriptor has no owner SID.
2424
/// </summary>
25-
public Principal Owner { get; private set; }
25+
public AccessControlPrincipal Owner { get; private set; }
2626

2727
/// <summary>
2828
/// Validates an access control list (ACL).
@@ -34,7 +34,7 @@ public sealed class AccessControlList : ObservableObject
3434
/// </summary>
3535
public ObservableCollection<AccessControlEntry> AccessControlEntries { get; private set; }
3636

37-
public AccessControlList(string path, bool isFolder, Principal owner, bool isValid)
37+
public AccessControlList(string path, bool isFolder, AccessControlPrincipal owner, bool isValid)
3838
{
3939
Path = path;
4040
IsFolder = isFolder;

Diff for: src/Files.App/Utils/Storage/Security/Principal.cs renamed to src/Files.App/Data/Items/AccessControlPrincipal.cs

+33-25
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
11
// Copyright (c) 2024 Files Community
22
// Licensed under the MIT License. See the LICENSE.
33

4-
using System.Text;
5-
using Vanara.PInvoke;
6-
using static Vanara.PInvoke.AdvApi32;
4+
using Windows.Win32;
5+
using Windows.Win32.Foundation;
6+
using Windows.Win32.Security;
77

8-
namespace Files.App.Utils.Storage
8+
namespace Files.App.Data.Items
99
{
1010
/// <summary>
1111
/// Represents a principal of an ACE or an owner of an ACL.
1212
/// </summary>
13-
public sealed class Principal : ObservableObject
13+
public sealed class AccessControlPrincipal : ObservableObject
1414
{
1515
/// <summary>
1616
/// Account type.
1717
/// </summary>
18-
public PrincipalType PrincipalType { get; private set; }
18+
public AccessControlPrincipalType PrincipalType { get; private set; }
1919

2020
/// <summary>
21-
/// Acount security identifier (SID).
21+
/// Account security identifier (SID).
2222
/// </summary>
2323
public string? Sid { get; private set; }
2424

@@ -43,8 +43,8 @@ public sealed class Principal : ObservableObject
4343
public string Glyph
4444
=> PrincipalType switch
4545
{
46-
PrincipalType.User => "\xE77B",
47-
PrincipalType.Group => "\xE902",
46+
AccessControlPrincipalType.User => "\xE77B",
47+
AccessControlPrincipalType.Group => "\xE902",
4848
_ => "\xE716",
4949
};
5050

@@ -66,26 +66,34 @@ public string? FullNameHumanized
6666
public string FullNameHumanizedWithBrackes
6767
=> string.IsNullOrEmpty(Domain) ? string.Empty : $"({Domain}\\{Name})";
6868

69-
public Principal(string sid)
69+
public unsafe AccessControlPrincipal(string sid)
7070
{
7171
if (string.IsNullOrEmpty(sid))
7272
return;
7373

7474
Sid = sid;
75-
var lpSid = ConvertStringSidToSid(sid);
75+
PSID lpSid = default;
76+
SID_NAME_USE snu = default;
7677

77-
StringBuilder lpName = new(), lpDomain = new();
78-
int cchName = 0, cchDomainName = 0;
78+
fixed (char* cSid = sid)
79+
PInvoke.ConvertStringSidToSid(new PCWSTR(cSid), &lpSid);
80+
81+
PWSTR lpName = default;
82+
PWSTR lpDomain = default;
83+
uint cchName = 0, cchDomainName = 0;
7984

8085
// Get size of account name and domain name
81-
bool bResult = LookupAccountSid(null, lpSid, lpName, ref cchName, lpDomain, ref cchDomainName, out _);
86+
bool bResult = PInvoke.LookupAccountSid(new PCWSTR(), lpSid, lpName, &cchName, lpDomain, &cchDomainName, null);
8287

8388
// Ensure requested capacity
84-
lpName.EnsureCapacity(cchName);
85-
lpDomain.EnsureCapacity(cchDomainName);
89+
fixed (char* cName = new char[cchName])
90+
lpName = new(cName);
91+
92+
fixed (char* cDomain = new char[cchDomainName])
93+
lpDomain = new(cDomain);
8694

8795
// Get account name and domain
88-
bResult = LookupAccountSid(null, lpSid, lpName, ref cchName, lpDomain, ref cchDomainName, out var snu);
96+
bResult = PInvoke.LookupAccountSid(new PCWSTR(), lpSid, lpName, &cchName, lpDomain, &cchDomainName, &snu);
8997
if(!bResult)
9098
return;
9199

@@ -96,24 +104,24 @@ var x when
96104
(x == SID_NAME_USE.SidTypeAlias ||
97105
x == SID_NAME_USE.SidTypeGroup ||
98106
x == SID_NAME_USE.SidTypeWellKnownGroup)
99-
=> PrincipalType.Group,
107+
=> AccessControlPrincipalType.Group,
100108

101109
// User
102110
SID_NAME_USE.SidTypeUser
103-
=> PrincipalType.User,
111+
=> AccessControlPrincipalType.User,
104112

105113
// Unknown
106-
_ => PrincipalType.Unknown
114+
_ => AccessControlPrincipalType.Unknown
107115
};
108116

109-
lpDomain.Clear();
110-
111117
// Replace domain name with computer name if the account type is user or alias type
112118
if (snu == SID_NAME_USE.SidTypeUser || snu == SID_NAME_USE.SidTypeAlias)
113119
{
114-
lpDomain = new(256, 256);
115-
uint size = (uint)lpDomain.Capacity;
116-
bResult = Kernel32.GetComputerName(lpDomain, ref size);
120+
uint size = 256;
121+
fixed (char* cDomain = new char[size])
122+
lpDomain = new(cDomain);
123+
124+
bResult = PInvoke.GetComputerName(lpDomain, ref size);
117125
if (!bResult)
118126
return;
119127
}

Diff for: src/Files.App/Utils/Storage/Security/AccessMaskItem.cs renamed to src/Files.App/Data/Items/AccessMaskItem.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright (c) 2024 Files Community
22
// Licensed under the MIT License. See the LICENSE.
33

4-
namespace Files.App.Utils.Storage
4+
namespace Files.App.Data.Items
55
{
66
/// <summary>
77
/// Represents an access mask details, such as its name and changeability.

Diff for: src/Files.App/Helpers/Application/AppLifecycleHelper.cs

+1
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ public static IHost ConfigureHost()
197197
.AddSingleton<IStartMenuService, StartMenuService>()
198198
.AddSingleton<IStorageCacheService, StorageCacheService>()
199199
.AddSingleton<IStorageArchiveService, StorageArchiveService>()
200+
.AddSingleton<IStorageSecurityService, StorageSecurityService>()
200201
.AddSingleton<IWindowsCompatibilityService, WindowsCompatibilityService>()
201202
// ViewModels
202203
.AddSingleton<MainPageViewModel>()

Diff for: src/Files.App/NativeMethods.json

-18
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,10 @@
1-
// Copyright (c) 2024 Files Community
2-
// Licensed under the MIT License. See the LICENSE.
31
{
42
"$schema": "https://aka.ms/CsWin32.schema.json",
5-
6-
// Emit COM interfaces instead of structs, and allow generation of non-blittable structs for the sake of an easier to use API.
73
"allowMarshaling": true,
8-
9-
// A value indicating whether to generate APIs judged to be unnecessary or redundant given the target framework.
10-
// This is useful for multi-targeting projects that need a consistent set of APIs across target frameworks
11-
// to avoid too many conditional compilation regions.
124
"multiTargetingFriendlyAPIs": false,
13-
14-
// A value indicating whether friendly overloads should use safe handles.
155
"useSafeHandles": true,
16-
17-
// Omit ANSI functions and remove `W` suffix from UTF-16 functions.
186
"wideCharOnly": true,
19-
20-
// A value indicating whether to emit a single source file as opposed to types spread across many files.
217
"emitSingleFile": false,
22-
23-
// The name of a single class under which all p/invoke methods and constants are generated, regardless of imported module.
248
"className": "PInvoke",
25-
26-
// A value indicating whether to expose the generated APIs publicly (as opposed to internally).
279
"public": true
2810
}

Diff for: src/Files.App/NativeMethods.txt

+19
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,22 @@ D3D11CreateDevice
7070
IDXGIDevice
7171
DCompositionCreateDevice
7272
IDCompositionDevice
73+
GetNamedSecurityInfo
74+
ConvertSidToStringSid
75+
ConvertStringSidToSid
76+
SetNamedSecurityInfo
77+
GetAclInformation
78+
IsValidAcl
79+
GetAce
80+
SetEntriesInAcl
81+
ACL_SIZE_INFORMATION
82+
DeleteAce
83+
EXPLICIT_ACCESS
84+
ACCESS_ALLOWED_ACE
85+
LookupAccountSid
86+
GetComputerName
87+
AddAccessAllowedAceEx
88+
LocalAlloc
89+
InitializeAcl
90+
AddAce
91+
LocalFree

0 commit comments

Comments
 (0)