[Win32API] How to change file owner.

0x5BFA 26 Reputation points
2021-05-21T04:40:52.887+00:00

Hi I'm making icacls command(It is windows file security utility) with C and Win32API.

So, when I try to implement the owner change, it fails with SetFileSecurity and GetLastError returns 1307.

What's wrong with this following code:

#include "Icacls.h"

BOOL SetFileOwner(LPWSTR lpFileName, LPWSTR lpUserName) {

    DWORD dwSecurityDescriptorSize = 0;

    // Get file security information size needed
    if (!GetFileSecurityW(lpFileName, OWNER_SECURITY_INFORMATION, NULL, 0, &dwSecurityDescriptorSize)) {

        // Buffer shortage
        if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {

            // Allocate memory
            PSECURITY_DESCRIPTOR pSecDesc = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, dwSecurityDescriptorSize + 1000);
            if (NULL == pSecDesc) {
                wprintf(L"LocalAlloc (pSecDesc) error: %d\n", GetLastError());
                return ERROR_NOT_ENOUGH_MEMORY;
            }

            // Start protected statement
            __try {

                // Get file security information with size needed
                if (!GetFileSecurityW(lpFileName, OWNER_SECURITY_INFORMATION, pSecDesc, dwSecurityDescriptorSize, &dwSecurityDescriptorSize)) {
                    wprintf(L"GetFileSecurityW error: %d\n", GetLastError());
                    __leave;
                }

                // Initialize security descriptor
                if (!InitializeSecurityDescriptor(pSecDesc, SECURITY_DESCRIPTOR_REVISION)) {
                    wprintf(L"InitializeSecurityDescriptor error: %d\n", GetLastError());
                    __leave;
                }

                BOOL bOwnerDefaulted = FALSE; PSID pNewSid = NULL;

                // Get account sid from username
                if (!GetAccountSid(lpUserName, &pNewSid, NULL)) {
                    wprintf(L"InitializeSecurityDescriptor error: %d\n", GetLastError());
                    __leave;
                }

                wprintf(L"lpUserName: %s\nlpFileName: %s\n\n", lpUserName, lpFileName);


                // Set file owner to local security descriptor
                if (!SetSecurityDescriptorOwner(pSecDesc, pNewSid, bOwnerDefaulted)) {
                    wprintf(L"SetSecurityDescriptorOwner error: %d\n", GetLastError());
                    __leave;
                }

                HANDLE hToken;
                GetTokenHandle(&hToken);
                AssertTakeOwnership(hToken);

                // Set security descriptor to file security
                if (!SetFileSecurityW(lpFileName, OWNER_SECURITY_INFORMATION, pSecDesc)) {
                    wprintf(L"SetFileSecurityW error: %d\n", GetLastError());
                    __leave;
                }

            }
            // Cleanup
            __finally {
                if (pSecDesc) LocalFree(pSecDesc);
                return GetLastError();
            }
        }
    }
}

BOOL GetTokenHandle(PHANDLE TokenHandle) {

    HANDLE ProcessHandle;
    BOOL Result;

    ProcessHandle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, GetCurrentProcessId());

    if (ProcessHandle == NULL) {
        return(FALSE);
    }

    Result = OpenProcessToken(ProcessHandle, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, TokenHandle);

    if (!Result) {
        CloseHandle(ProcessHandle);
        return FALSE;
    }

    CloseHandle(ProcessHandle);
    return(TRUE);
}

BOOL AssertTakeOwnership(HANDLE TokenHandle) {

    LUID TakeOwnershipValue;
    BOOL Result;
    TOKEN_PRIVILEGES TokenPrivileges;

    Result = LookupPrivilegeValueW(NULL, L"SeTakeOwnershipPrivilege", &TakeOwnershipValue);

    if (!Result) {
        return FALSE;
    }

    TokenPrivileges.PrivilegeCount = 1;
    TokenPrivileges.Privileges[0].Luid = TakeOwnershipValue;
    TokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

    (VOID)AdjustTokenPrivileges(TokenHandle, FALSE, &TokenPrivileges, sizeof(TOKEN_PRIVILEGES), NULL, NULL);

    if (GetLastError() != NO_ERROR) {
        return FALSE;
    }

    return(TRUE);
}
Windows development | Windows API - Win32
0 comments No comments
{count} vote

Answer accepted by question author
  1. Xiaopo Yang - MSFT 12,736 Reputation points Microsoft External Staff
    2021-05-21T08:16:41.033+00:00

    According to MSDN:SE_RESTORE_NAME and this thread, It's necessary to enable SE_RESTORE_NAME privilege which enables you to set any valid user or group SID as the owner of a file.

    Additionally, It is recommend to use SetNamedSecurityInfo.


0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.