• 0

Change file and folder owner from .NET


Question

Hello, can anyone help me change a folder or file's owner from .NET on windows 2003? I have found a program called subinacl.exe that does this but if is too slow to shell out and execute this. Also if it can be done to subfolders automatically without me going through all the folders it would be great.

Thanks in advance :D

9 answers to this question

Recommended Posts

  • 0

private static void GiveControl(string path, string user, ACCESS_MASK access)
{
	IntPtr sd = IntPtr.Zero;
	IntPtr daclNew = IntPtr.Zero;
	IntPtr eaNew = IntPtr.Zero;

	try
	{
  int err;

  IntPtr daclOld;
  IntPtr unused1, unused2, unused3;
  if ((err = GetNamedSecurityInfo(path, SE_OBJECT_TYPE.FILE, SECURITY_INFORMATION.DACL, out unused1, out unused2, out daclOld, out unused3, out sd)) != 0)
 	 throw new Win32Exception(err);


  if ((eaNew = LocalAlloc(0, 64)) == IntPtr.Zero)
 	 throw new Win32Exception(Marshal.GetLastWin32Error());

  BuildExplicitAccessWithName(eaNew, user, access, ACCESS_MODE.GRANT, INHERITANCE.CONTAINER | INHERITANCE.OBJECT);

  if ((err = SetEntriesInAcl(1, eaNew, daclOld, out daclNew)) != 0) throw new Win32Exception(err);

  if ((err = SetNamedSecurityInfo(path, SE_OBJECT_TYPE.FILE, SECURITY_INFORMATION.DACL, IntPtr.Zero, IntPtr.Zero, daclNew, IntPtr.Zero)) != 0)
 	 throw new Win32Exception(err);

	}
	finally
	{
  LocalFree(sd);
  LocalFree(eaNew);
  LocalFree(daclNew);
	}
}
  
  
private enum ACCESS_MODE : uint
{
	NOT_USED = 0,
	GRANT,
	SET,
	DENY,
	REVOKE,
	SET_AUDIT_SUCCESS,
	SET_AUDIT_FAILURE
}

[Flags]
private enum ACCESS_MASK : uint
{
	EXCLUSIVE = 0x200,
	READDESIGN = 0x400,
	WRITEDESIGN = 0x800,
	WITHGRANT = 0x1000,
	REFERENCE = 0x2000,
	CREATE = 0x4000,
	INSERT = 0x8000,
	DELETE = 0x10000,
	READCONTROL = 0x20000,
	WRITEPERMISSIONS = 0x40000,
	WRITEOWNER = 0x80000,
	MAXIMUM_ALLOWED = 0x2000000,
	ALL = 0x10000000,
	EXECUTE = 0x20000000,
	READ = 0x80000000,
	UPDATE = 0x40000000,
	DROP = 0x100
}

[Flags]
private enum INHERITANCE : uint
{
	OBJECT = 0x1,
	CONTAINER = 0x2,
	NO_PROPAGATE = 0x4,
	INHERIT_ONLY = 0x8,
	INHERITED = 0x10,
	VALID_FLAGS = 0x1F
}

private enum SE_OBJECT_TYPE : uint
{
	UNKNOWN = 0,
	FILE,
	SERVICE,
	PRINTER,
	REGISTRY_KEY,
	LMSHARE,
	KERNEL,
	WINDOW,
	DS,
	DS_ALL,
	PROVIDER_DEFINED,
	WMIGUID,
	REGISTRY_WOW64_32KEY
}

public enum SECURITY_INFORMATION : uint
{
	OWNER = 0x00000001,
	GROUP = 0x00000002,
	DACL = 0x00000004,
	SACL = 0x00000008,

	PROTECTED_DACL = 0x80000000,
	PROTECTED_SACL = 0x40000000,
	UNPROTECTED_DACL = 0x20000000,
	UNPROTECTED_SACL = 0x10000000
}

[DllImport("advapi32.dll", CallingConvention=CallingConvention.Winapi, CharSet=CharSet.Auto)]
private static extern int GetNamedSecurityInfo([In] string pObjectName, [In] SE_OBJECT_TYPE ObjectType, [In] SECURITY_INFORMATION SecurityInfo, [Out] out IntPtr ppsidOwner, [Out] out IntPtr ppsidGroup, [Out] out IntPtr ppDacl, [Out] out IntPtr ppSacl, [Out] out IntPtr ppSecurityDescriptor);  

[DllImport("kernel32.dll", CallingConvention=CallingConvention.Winapi, SetLastError=true, CharSet=CharSet.Auto)]
private static extern IntPtr LocalAlloc([In] uint uFlags, [In] uint uBytes);  


[DllImport("advapi32.dll", CallingConvention=CallingConvention.Winapi,	CharSet=CharSet.Auto)]
private static extern void BuildExplicitAccessWithName([In] IntPtr pExplicitAccess, [In] string pTrusteeName, [In] ACCESS_MASK AccessPermissions, [In] ACCESS_MODE AccessMode, [In] INHERITANCE Inheritance);  


[DllImport("advapi32.dll", CallingConvention=CallingConvention.Winapi, CharSet=CharSet.Auto)]
private static extern int SetEntriesInAcl([In] uint cCountOfExplicitEntries, [In] IntPtr pListOfExplicitEntries, [In] IntPtr OldAcl, [Out] out IntPtr NewAcl);

[DllImport("advapi32.dll", CallingConvention=CallingConvention.Winapi, CharSet=CharSet.Auto)]
private static extern int SetNamedSecurityInfo([In] string pObjectName, [In] SE_OBJECT_TYPE ObjectType, [In] SECURITY_INFORMATION SecurityInfo, [In] IntPtr psidOwner, [In] IntPtr psidGroup, [In] IntPtr pDacl, [In] IntPtr pSacl);

[DllImport("kernel32.dll", CallingConvention=CallingConvention.Winapi, SetLastError=true, CharSet=CharSet.Auto)]
private static extern IntPtr LocalFree([In] IntPtr hMem);

You can assign rights by calling something like

GiveControl(@"C:\Windows", Environment.GetEnvironmentVariable("COMPUTERNAME") + "\Administrator", ACCESS_MASK.ALL);

  • 0

This is what I want to do: On Windows 2003 I have a MySQL Server, and Quota mangement on that drive. I have a windows account named 'demo' with 10mb quota. I create a database named demo and give access to that user. He can create, drop tables, write data. The problem is that when he creates a table, the owner of this file is not 'demo' it is 'Administrators' because it is created by the local service account, so his quota is not updated. What I want to do is create a windows service that changes the owner of these files to 'demo' so his quota is updated. I could create a batch file but I would have to be updating it for every user that I create. Also, it's not just the mySQL database folder, The user also has a folder where anyone can create files and folders, but the owner must still be 'demo' The folder structure is something like this:

d:\mysql\data\<user>

d:\userFiles\<user>\shared

d:\userFiles\<user>\private

EDIT: But your first code will help me on some other stuff I want to do, so thanks :D

  • 0

I found this vbscript example that changes the owner but I get the error:

  Quote
"This security ID may not be assigned as the owner of this object"

set oADsSecurity = CreateObject("ADsSecurityUtility")
Set sd = oADsSecurity.GetSecurityDescriptor("c:\test.txt", 1, 1)
wscript.echo sd.Owner
oADsSecurity.SecurityMask = 1
sd.Owner = "Domain\User"
oADsSecurity.SetSecurityDescriptor "c:\test.txt", 1, sd, 1

It only seems to work when I want to take ownership of a file, not when I want tp asign ownership to another user. :o

  • 0

I found a way to do it. It was on msdn .net documentation all along :blush: ms-help://MS.VSCC.2003/MS.MSDNQTR.2003APR.1033/enu_kbwin32sdk/win32sdk/318744.htm

It's on visual basic 6 but I made an com dll out of it and it's working great.

Thanks for your help and patience :p

Option Explicit

' Global constants we must use with security descriptor
Private Const SECURITY_DESCRIPTOR_REVISION = 1
Private Const OWNER_SECURITY_INFORMATION = 1&amp;

' Access Token constants
Private Const TOKEN_ASSIGN_PRIMARY = &amp;H1
Private Const TOKEN_DUPLICATE = &amp;H2
Private Const TOKEN_IMPERSONATE = &amp;H4
Private Const TOKEN_QUERY = &amp;H8
Private Const TOKEN_QUERY_SOURCE = &amp;H10
Private Const TOKEN_ADJUST_PRIVILEGES = &amp;H20
Private Const TOKEN_ADJUST_GROUPS = &amp;H40
Private Const TOKEN_ADJUST_DEFAULT = &amp;H80
Private Const TOKEN_ALL_ACCESS = TOKEN_ASSIGN_PRIMARY _
      + TOKEN_DUPLICATE + TOKEN_IMPERSONATE + TOKEN_QUERY _
      + TOKEN_QUERY_SOURCE + TOKEN_ADJUST_PRIVILEGES _
      + TOKEN_ADJUST_GROUPS + TOKEN_ADJUST_DEFAULT
Private Const ANYSIZE_ARRAY = 1

' Token Privileges constants
Private Const SE_RESTORE_NAME = "SeRestorePrivilege"
Private Const SE_PRIVILEGE_ENABLED = 2&amp;

' ACL structure
Private Type ACL
   AclRevision As Byte
   Sbz1 As Byte
   AclSize As Integer
   AceCount As Integer
   Sbz2 As Integer
End Type

Private Type SECURITY_DESCRIPTOR
   Revision As Byte
   Sbz1 As Byte
   Control As Long
   Owner As Long
   Group As Long
   Sacl As ACL
   Dacl As ACL
End Type

' Token structures
Private Type LARGE_INTEGER
   lowpart As Long
   highpart As Long
End Type

Private Type LUID
   lowpart As Long
   highpart As Long
End Type

Private Type LUID_AND_ATTRIBUTES
   pLuid As LUID
   Attributes As Long
End Type

Private Type TOKEN_PRIVILEGES
   PrivilegeCount As Long
   Privileges(ANYSIZE_ARRAY) As LUID_AND_ATTRIBUTES
End Type

' Win32 API calls
Private Declare Function LookupAccountName Lib "advapi32.dll" _
      Alias "LookupAccountNameA" (ByVal lpSystemName As String, _
      ByVal lpAccountName As String, Sid As Byte, cbSid As Long, _
      ByVal ReferencedDomainName As String, _
      cbReferencedDomainName As Long, peUse As Integer) As Long
      
Private Declare Function InitializeSecurityDescriptor _
      Lib "advapi32.dll" (pSecurityDescriptor As SECURITY_DESCRIPTOR, _
      ByVal dwRevision As Long) As Long
      
Private Declare Function SetSecurityDescriptorOwner _
      Lib "advapi32.dll" (pSecurityDescriptor As SECURITY_DESCRIPTOR, _
      pOwner As Any, ByVal bOwnerDefaulted As Long) As Long
      
Private Declare Function SetFileSecurity Lib "advapi32.dll" _
      Alias "SetFileSecurityA" (ByVal lpFileName As String, _
      ByVal SecurityInformation As Long, _
      pSecurityDescriptor As SECURITY_DESCRIPTOR) As Long
      
Private Declare Function OpenProcessToken Lib "advapi32.dll" _
      (ByVal ProcessHandle As Long, ByVal DesiredAccess As Long, _
      TokenHandle As Long) As Long
      
Private Declare Function GetCurrentProcess Lib "kernel32" () As Long

Private Declare Function LookupPrivilegeValue Lib "advapi32.dll" _
      Alias "LookupPrivilegeValueA" (ByVal lpSystemName As String, _
      ByVal lpName As String, lpLuid As LUID) As Long
      
Private Declare Function AdjustTokenPrivileges Lib "advapi32.dll" _
      (ByVal TokenHandle As Long, ByVal DisableAllPrivileges As Long, _
      NewState As TOKEN_PRIVILEGES, ByVal BufferLength As Long, _
      ByVal PreviousState As Long, ByVal ReturnLength As Long) As Long
      
Private Declare Function CloseHandle Lib "kernel32" _
      (ByVal hObject As Long) As Long

Public Sub ChangeOwnerOfFile(FileName As String, _
      OwnerAccountName As String)

   ' variables for the LookupAccountName API Call
   Dim Sid(255) As Byte             ' Buffer for the SID
   Dim nBufferSize As Long          ' Length of SID Buffer
   Dim szDomainName As String * 255 ' Domain Name Buffer
   Dim nDomain As Long              ' Length of Domain Name buffer
   Dim peUse As Integer             ' SID type
   Dim Result As Long               ' Return value of Win32 API call
   
   ' variables for the InitializeSecurityDescriptor API Call
   Dim SecDesc As SECURITY_DESCRIPTOR
   Dim Revision As Long
   
   Enable_Privilege (SE_RESTORE_NAME)
   
   nBufferSize = 255
   nDomain = 255
   
   Result = LookupAccountName(vbNullString, OwnerAccountName, _
         Sid(0), nBufferSize, szDomainName, nDomain, peUse)
   If (Result = 0) Then
      MsgBox "LookupAccountName failed with error code " _
            &amp; Err.LastDllError
      Exit Sub
   End If
   
   Result = InitializeSecurityDescriptor(SecDesc, _
         SECURITY_DESCRIPTOR_REVISION)
   If (Result = 0) Then
      MsgBox "InitializeSecurityDescriptor failed with error code " _
            &amp; Err.LastDllError
      Exit Sub
   End If
   
   Result = SetSecurityDescriptorOwner(SecDesc, Sid(0), 0)
   If (Result = 0) Then
      MsgBox "SetSecurityDescriptorOwner failed with error code " _
            &amp; Err.LastDllError
      Exit Sub
   End If
   
   Result = SetFileSecurity(FileName, OWNER_SECURITY_INFORMATION, _
         SecDesc)
   If (Result = 0) Then
      MsgBox "SetFileSecurity failed with error code " _
            &amp; Err.LastDllError
      Exit Sub
   Else
      MsgBox "Owner of " &amp; FileName &amp; " changed to " _
            &amp; OwnerAccountName
   End If
   
   Disable_Privilege (SE_RESTORE_NAME)
   
End Sub

Public Function Enable_Privilege(Privilege As String) As Boolean
   Enable_Privilege = ModifyState(Privilege, True)
End Function

Public Function Disable_Privilege(Privilege As String) As Boolean
   Disable_Privilege = ModifyState(Privilege, False)
End Function

Public Function ModifyState(Privilege As String, _
      Enable As Boolean) As Boolean
    
   Dim MyPrives As TOKEN_PRIVILEGES
   Dim PrivilegeId As LUID
   Dim ptrPriv As Long    ' Pointer to Privileges Structure
   Dim hToken As Long     ' Token Handle
   Dim Result As Long     ' Return Value
   
   Result = OpenProcessToken(GetCurrentProcess(), _
         TOKEN_ADJUST_PRIVILEGES, hToken)
   If (Result = 0) Then
      ModifyState = False
      MsgBox "OpenProcessToken failed with error code " _
            &amp; Err.LastDllError
      Exit Function
   End If
   
   Result = LookupPrivilegeValue(vbNullString, Privilege, PrivilegeId)
   If (Result = 0) Then
      ModifyState = False
      MsgBox "LookupPrivilegeValue failed with error code " _
            &amp; Err.LastDllError
      Exit Function
   End If
   
   MyPrives.Privileges(0).pLuid = PrivilegeId
   MyPrives.PrivilegeCount = 1
   If (Enable) Then
      MyPrives.Privileges(0).Attributes = SE_PRIVILEGE_ENABLED
   Else
      MyPrives.Privileges(0).Attributes = 0
   End If
    
   Result = AdjustTokenPrivileges(hToken, False, MyPrives, 0, 0, 0)
   If (Result = 0 Or Err.LastDllError &lt;&gt; 0) Then
      ModifyState = False
      MsgBox "AdjustTokenPrivileges failed with error code " _
            &amp; Err.LastDllError
      Exit Function
   End If
   
   CloseHandle hToken
   
   ModifyState = True

End Function

This topic is now closed to further replies.
  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Posts

    • Microsoft reportedly planning to lay off thousands of employees, mostly in sales by Usama Jawad Back in May 2025, Microsoft decided to lay off 3% of its workforce, which amounted to roughly 6,000 employees. It claimed that this decision allowed it to implement better organizational changes in a "dynamic marketplace". Now, a new report claims that the Redmond tech firm is planning to lay off thousands more next month. Citing unnamed sources, Bloomberg reports that as the company continues investing heavily in its AI ventures, it is about to announce layoffs of thousands of workers as early as next month. This reduction in workforce will primarily affect sales teams, but they won't be the only ones affected. That said, the sources did mention that the timing for this announcement may change. This move, if true, won't be entirely surprising. In April 2025, Microsoft announced that it will be relying more on third-party firms to sell its software to small- and medium-sized customers. It's currently unclear how many employees will be impacted by this change, but even if the layoff percentage is in the single digits, it would still be significant as it would be impacting the professional careers of thousands. The May 2025 layoffs primarily impacted engineering and product teams. The other major round of layoffs prior to this was the decision to eliminate 10,000 jobs back in January 2023. Those represented 5% of the total workforce at that time, with numerous teams, including the one leading Mixed Reality (MR) efforts, being heavily impacted. It is interesting to note that if the timing of the announcement for layoffs is accurate, it would be soon after Microsoft closes its fiscal year at the end of June 2025. Although we'll get financial reports for the latest quarter soon after too, one has to wonder what the human cost of profit is, as Microsoft continues to report billions of dollars in revenue every quarter. Source: Bloomberg (paywall)
    • Ah .. lockout for suspicious activity. I bet they uploaded the SanDisk utility detected as malware
    • Microsoft 365 will soon disable outdated authentication protocols for file access by Usama Jawad On a fairly regular basis, Microsoft disables outdated protocols that are used to access its services. In the past few years, the company has deprecated Basic Auth in Exchange Online and cut access to Outlook for third-party apps relying on this protocol. Now, it has decided to get rid of old authentication protocols for file access across Microsoft 365 services. As reported by Bleeping Computer, Microsoft has posted a message on its Microsoft 365 Admin Center. Starting from mid-July 2025, the company will begin disabling legacy authentication protocols used to access files across Microsoft 365 and Office apps, SharePoint, and OneDrive. Essentially, applications or services which use the Relying Party Suite (RPS) or FrontPage Remote Procedure Call (FPRPC) will to perform browser-based authentication to perform open operations on Office files will no longer be able to do so. As expected, this is primarily being done to improve the cybersecurity posture of various services. Microsoft states that RPS can be brute-forced and phished with relative ease as it is fairly outdated. Similarly, FPRPC is typically used for remote web page authoring and it is susceptible to exploitation through various vulnerabilities too. As such, both of these protocols will be disabled by default starting from mid-July 2025, with the rollout of this change targeting completion by August 2025. The Redmond tech giant will update the protocol baseline by default without mandating any licensing changes for customers. In addition, once these modifications are rolled out, Microsoft 365 will require admin consent to get third-party access to files and sites. IT admins can view the guidance available here to configure admin consent workflows. Microsoft says that these changes align with the principles of its Secure Future Initiative (SFI). Earlier today, it announced the rollout of improved security defaults for Windows 365 citing the same reasons too.
    • This is how you kill your own business.
  • Recent Achievements

    • First Post
      Fuzz_c earned a badge
      First Post
    • First Post
      TIGOSS earned a badge
      First Post
    • Week One Done
      slackerzz earned a badge
      Week One Done
    • Week One Done
      vivetool earned a badge
      Week One Done
    • Reacting Well
      pnajbar earned a badge
      Reacting Well
  • Popular Contributors

    1. 1
      +primortal
      705
    2. 2
      ATLien_0
      283
    3. 3
      Michael Scrip
      216
    4. 4
      +FloatingFatMan
      194
    5. 5
      Steven P.
      130
  • Tell a friend

    Love Neowin? Tell a friend!