Getting/Setting File Owner in C#

Getting / setting file owner in C#

No need to P/Invoke. System.IO.File.GetAccessControl will return a FileSecurity object, which has a GetOwner method.

Edit: Reading the owner is pretty simple, though it's a bit of a cumbersome API:

const string FILE = @"C:\test.txt";

var fs = File.GetAccessControl(FILE);

var sid = fs.GetOwner(typeof(SecurityIdentifier));
Console.WriteLine(sid); // SID

var ntAccount = sid.Translate(typeof(NTAccount));
Console.WriteLine(ntAccount); // DOMAIN\username

Setting the owner requires a call to SetAccessControl to save the changes. Also, you're still bound by the Windows rules of ownership - you can't assign ownership to another account. You can give take ownership perms, and they have to take ownership.

var ntAccount = new NTAccount("DOMAIN", "username");
fs.SetOwner(ntAccount);

try {
File.SetAccessControl(FILE, fs);
} catch (InvalidOperationException ex) {
Console.WriteLine("You cannot assign ownership to that user." +
"Either you don't have TakeOwnership permissions, or it is not your user account."
);
throw;
}

Find out File Owner/Creator in C#

string user = System.IO.File.GetAccessControl(path).GetOwner(typeof(System.Security.Principal.NTAccount)).ToString();

[EDIT] for newer .net versions, you will need to install System.IO.FileSystem.AccessControl

How to set the owner of a file to SYSTEM?

With the help of Christian.K who pointed me towards AdjustTokenPrivileges and SE_RESTORE_NAME, all that needs to be done is to enable this privilege on the process token:

// Allow this process to circumvent ACL restrictions
WinAPI.ModifyPrivilege(PrivilegeName.SeRestorePrivilege, true);

// Sometimes this is required and other times it works without it. Not sure when.
WinAPI.ModifyPrivilege(PrivilegeName.SeTakeOwnershipPrivilege, true);

// Set owner to SYSTEM
var fs = IO.File.GetAccessControl(path);
fs.SetOwner(new NTAccount("NT AUTHORITY\\SYSTEM"));
IO.File.SetAccessControl(path, fs);

Here is the code for such a ModifyPrivilege helper method:

static class WinAPI
{
/// <summary>
/// Enables or disables the specified privilege on the primary access token of the current process.</summary>
/// <param name="privilege">
/// Privilege to enable or disable.</param>
/// <param name="enable">
/// True to enable the privilege, false to disable it.</param>
/// <returns>
/// True if the privilege was enabled prior to the change, false if it was disabled.</returns>
public static bool ModifyPrivilege(PrivilegeName privilege, bool enable)
{
LUID luid;
if (!LookupPrivilegeValue(null, privilege.ToString(), out luid))
throw new Win32Exception();

using (var identity = WindowsIdentity.GetCurrent(TokenAccessLevels.AdjustPrivileges | TokenAccessLevels.Query))
{
var newPriv = new TOKEN_PRIVILEGES();
newPriv.Privileges = new LUID_AND_ATTRIBUTES[1];
newPriv.PrivilegeCount = 1;
newPriv.Privileges[0].Luid = luid;
newPriv.Privileges[0].Attributes = enable ? SE_PRIVILEGE_ENABLED : 0;

var prevPriv = new TOKEN_PRIVILEGES();
prevPriv.Privileges = new LUID_AND_ATTRIBUTES[1];
prevPriv.PrivilegeCount = 1;
uint returnedBytes;

if (!AdjustTokenPrivileges(identity.Token, false, ref newPriv, (uint) Marshal.SizeOf(prevPriv), ref prevPriv, out returnedBytes))
throw new Win32Exception();

return prevPriv.PrivilegeCount == 0 ? enable /* didn't make a change */ : ((prevPriv.Privileges[0].Attributes & SE_PRIVILEGE_ENABLED) != 0);
}
}

const uint SE_PRIVILEGE_ENABLED = 2;

[DllImport("advapi32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool AdjustTokenPrivileges(IntPtr TokenHandle, [MarshalAs(UnmanagedType.Bool)] bool DisableAllPrivileges, ref TOKEN_PRIVILEGES NewState,
UInt32 BufferLengthInBytes, ref TOKEN_PRIVILEGES PreviousState, out UInt32 ReturnLengthInBytes);

[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool LookupPrivilegeValue(string lpSystemName, string lpName, out LUID lpLuid);

struct TOKEN_PRIVILEGES
{
public UInt32 PrivilegeCount;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1 /*ANYSIZE_ARRAY*/)]
public LUID_AND_ATTRIBUTES[] Privileges;
}

[StructLayout(LayoutKind.Sequential)]
struct LUID_AND_ATTRIBUTES
{
public LUID Luid;
public UInt32 Attributes;
}

[StructLayout(LayoutKind.Sequential)]
struct LUID
{
public uint LowPart;
public int HighPart;
}
}

enum PrivilegeName
{
SeAssignPrimaryTokenPrivilege,
SeAuditPrivilege,
SeBackupPrivilege,
SeChangeNotifyPrivilege,
SeCreateGlobalPrivilege,
SeCreatePagefilePrivilege,
SeCreatePermanentPrivilege,
SeCreateSymbolicLinkPrivilege,
SeCreateTokenPrivilege,
SeDebugPrivilege,
SeEnableDelegationPrivilege,
SeImpersonatePrivilege,
SeIncreaseBasePriorityPrivilege,
SeIncreaseQuotaPrivilege,
SeIncreaseWorkingSetPrivilege,
SeLoadDriverPrivilege,
SeLockMemoryPrivilege,
SeMachineAccountPrivilege,
SeManageVolumePrivilege,
SeProfileSingleProcessPrivilege,
SeRelabelPrivilege,
SeRemoteShutdownPrivilege,
SeRestorePrivilege,
SeSecurityPrivilege,
SeShutdownPrivilege,
SeSyncAgentPrivilege,
SeSystemEnvironmentPrivilege,
SeSystemProfilePrivilege,
SeSystemtimePrivilege,
SeTakeOwnershipPrivilege,
SeTcbPrivilege,
SeTimeZonePrivilege,
SeTrustedCredManAccessPrivilege,
SeUndockPrivilege,
SeUnsolicitedInputPrivilege,
}

Set running user as file owner and delete it in .NET Core

Thanks to Heretic Monkey comment and the information from various StackOverflow post, I compiled the solution both for setting the file/folder owner and reset its attributes (i.e readonly, system):

public static class CoreUtils
{

public static string RunningUser { get; } = $"{Environment.UserDomainName}\\{Environment.UserName}";
public static NTAccount RunningAccount { get; } = new NTAccount(Environment.UserDomainName, Environment.UserName);

}

void SetOwner(FileInfo file)
{
var acl = file.GetAccessControl(System.Security.AccessControl.AccessControlSections.All);

acl.SetOwner(CoreUtils.RunningAccount);
acl.AddAccessRule(new System.Security.AccessControl.FileSystemAccessRule(
CoreUtils.RunningUser, System.Security.AccessControl.FileSystemRights.FullControl, System.Security.AccessControl.AccessControlType.Allow));

file.SetAccessControl(acl);
}

Also a note is that as in linked article, the API does not support long file name so you need extra processing if your app needs to work with these files.

How to write name of the file's owner to the file using c#?

From this question

File.Copy(@"1.txt", @"2.txt", true);
string userName = System.IO.File.GetAccessControl(@"1.txt").GetOwner(typeof(System.Security.Principal.NTAccount)).ToString();
var fs = File.GetAccessControl(@"2.txt");
var ntAccount = new NTAccount("DOMAIN", userName);
fs.SetOWner(ntAccount);

try {
File.SetAccessControl(@"2.txt", fs);
} catch (InvalidOperationException ex) {
Console.WriteLine("You cannot assign ownership to that user." +
"Either you don't have TakeOwnership permissions, or it is not your user account."
);
throw;
}

get the file owner information using c#

Sorry for a couple of answers I placed in the wrong spot. Am new to this site (and c#/.net if you cant tell) I believe I have found a solution here Getting / setting file owner in C# Based on that this is how I have it working:

using System.Security.AccessControl;
using System.Security.Principal;

var fs = System.IO.File.GetAccessControl(fileName);
var sid = fs.GetOwner(typeof(SecurityIdentifier));
Console.WriteLine(sid);
var ntAccount = sid.Translate(typeof(NTAccount));
Console.WriteLine(ntAccount);

so ntAccount is may variable which I will use in the SQL for the document owners name. Thanks for every ones time helping me here. This solution does seem to be working. Quick question since im new here. Should I have posted this as a reply and should I accept it?



Related Topics



Leave a reply



Submit