Microsoft KB Archive/318744

= How To Use Visual Basic to Programmatically Change Ownership of a File or Folder =

Article ID: 318744

Article Last Modified on 11/21/2006

-

APPLIES TO

 Microsoft Win32 Application Programming Interface, when used with:  Microsoft Windows NT 4.0

 Microsoft Windows 2000 Standard Edition

 Microsoft Windows XP Professional 

-

<div class="notice_section">

This article was previously published under Q318744

<div class="summary_section">

SUMMARY
This article explains how to call the low-level access control functions from Microsoft Visual Basic to change ownership of a file or folder.

<div class="moreinformation_section">

MORE INFORMATION
If a user has been granted the SE_RESTORE_NAME privilege (&quot;Restore files and directories&quot;), that user can change the owner of a file or folder on a secure file system. By default, Administrators and Backup Operators hold the SE_RESTORE_NAME privilege.

In addition to being present in the process access token, the SE_RESTORE_NAME privilege must also be granted (enabled). You can grant this privilege by using the AdjustTokenPrivileges function. After the privilege has been granted, the process can set any valid user or group SID as the owner of a file or folder.

Sample Code
The following sample Visual Basic code demonstrates how to grant the SE_RESTORE_NAME privilege and then set the owner of a file or directory. The ChangeOwnerOfFile function takes a file or folder name and a user name. It then makes the specified user the owner of the specified file or folder.

NOTE: This code is useful only when targeting files or folders that reside on a secure file system, such as NTFS. The FAT and FAT32 file systems are not secure, and therefore, files on these file systems do not have owners.

Option Explicit

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

' Access Token constants Private Const TOKEN_ASSIGN_PRIMARY = &H1 Private Const TOKEN_DUPLICATE = &H2 Private Const TOKEN_IMPERSONATE = &H4 Private Const TOKEN_QUERY = &H8 Private Const TOKEN_QUERY_SOURCE = &H10 Private Const TOKEN_ADJUST_PRIVILEGES = &H20 Private Const TOKEN_ADJUST_GROUPS = &H40 Private Const TOKEN_ADJUST_DEFAULT = &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 = &quot;SeRestorePrivilege&quot; Private Const SE_PRIVILEGE_ENABLED = 2&

' 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 &quot;advapi32.dll&quot; _ Alias &quot;LookupAccountNameA&quot; (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 &quot;advapi32.dll&quot; (pSecurityDescriptor As SECURITY_DESCRIPTOR, _     ByVal dwRevision As Long) As Long Private Declare Function SetSecurityDescriptorOwner _ Lib &quot;advapi32.dll&quot; (pSecurityDescriptor As SECURITY_DESCRIPTOR, _     pOwner As Any, ByVal bOwnerDefaulted As Long) As Long Private Declare Function SetFileSecurity Lib &quot;advapi32.dll&quot; _ Alias &quot;SetFileSecurityA&quot; (ByVal lpFileName As String, _     ByVal SecurityInformation As Long, _      pSecurityDescriptor As SECURITY_DESCRIPTOR) As Long Private Declare Function OpenProcessToken Lib &quot;advapi32.dll&quot; _ (ByVal ProcessHandle As Long, ByVal DesiredAccess As Long, _     TokenHandle As Long) As Long Private Declare Function GetCurrentProcess Lib &quot;kernel32&quot; As Long

Private Declare Function LookupPrivilegeValue Lib &quot;advapi32.dll&quot; _ Alias &quot;LookupPrivilegeValueA&quot; (ByVal lpSystemName As String, _     ByVal lpName As String, lpLuid As LUID) As Long Private Declare Function AdjustTokenPrivileges Lib &quot;advapi32.dll&quot; _ (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 &quot;kernel32&quot; _ (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 &quot;LookupAccountName failed with error code &quot; _ & Err.LastDllError Exit Sub End If  Result = InitializeSecurityDescriptor(SecDesc, _         SECURITY_DESCRIPTOR_REVISION) If (Result = 0) Then MsgBox &quot;InitializeSecurityDescriptor failed with error code &quot; _ & Err.LastDllError Exit Sub End If  Result = SetSecurityDescriptorOwner(SecDesc, Sid(0), 0) If (Result = 0) Then MsgBox &quot;SetSecurityDescriptorOwner failed with error code &quot; _ & Err.LastDllError Exit Sub End If  Result = SetFileSecurity(FileName, OWNER_SECURITY_INFORMATION, _         SecDesc) If (Result = 0) Then MsgBox &quot;SetFileSecurity failed with error code &quot; _ & Err.LastDllError Exit Sub Else MsgBox &quot;Owner of &quot; & FileName & &quot; changed to &quot; _ & 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 &quot;OpenProcessToken failed with error code &quot; _ & Err.LastDllError Exit Function End If  Result = LookupPrivilegeValue(vbNullString, Privilege, PrivilegeId) If (Result = 0) Then ModifyState = False MsgBox &quot;LookupPrivilegeValue failed with error code &quot; _ & 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 <> 0) Then ModifyState = False MsgBox &quot;AdjustTokenPrivileges failed with error code &quot; _ & Err.LastDllError Exit Function End If  CloseHandle hToken ModifyState = True

End Function

<div class="references_section">