2014年3月30日星期日

给文件添加用户(组)及权限

/*
文件名:SetNamedSecurityInfo.cpp
功能:给一个文件/文件夹(其他的对象也可以)添加用户(组)及访问的权限.

这是一个基本的功能,岂能不会.
其实系统自带的文件有此功能,但是搞编程的,特别是系统编程的,岂能用脚本.
所以有此文,早就想有此文了.
微软的代码只是示例,自己想要的功能要自己动手.

微软的说明:
The following example tries to change the DACL of a file object by taking ownership of that object.
This will succeed only if the caller has WRITE_DAC access to the object or is the owner of the object.
If the initial attempt to change the DACL fails, an administrator can take ownership of the object.
To give the administrator ownership, the example enables the SE_TAKE_OWNERSHIP_NAME privilege in the caller's access token,
and makes the local system's Administrators group the owner of the object.
If the caller is a member of the Administrators group, the code will then be able to change the object's DACL.

参考:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa379620(v=vs.85).aspx
http://msdn.microsoft.com/en-us/library/windows/desktop/aa446619(v=vs.85).aspx

made by correy
made at 2014.03.30
email:kouleguan at hotmail dot com
homepage:http://correy.webs.com
*/

#include <aclapi.h>
#include <Mq.h>

HRESULT GetSid(LPCWSTR wszAccName, PSID * ppSid)
{
    // Validate the input parameters.
    if (wszAccName == NULL || ppSid == NULL) {
        return MQ_ERROR_INVALID_PARAMETER;
    }

    // Create buffers that may be large enough.
    // If a buffer is too small, the count parameter will be set to the size needed.
    const DWORD INITIAL_SIZE = 32;
    DWORD cbSid = 0;
    DWORD dwSidBufferSize = INITIAL_SIZE;
    DWORD cchDomainName = 0;
    DWORD dwDomainBufferSize = INITIAL_SIZE;
    WCHAR * wszDomainName = NULL;
    SID_NAME_USE eSidType;
    DWORD dwErrorCode = 0;
    HRESULT hr = MQ_OK;

    // Create buffers for the SID and the domain name.
    *ppSid = (PSID) new BYTE[dwSidBufferSize];
    if (*ppSid == NULL)  {
        return MQ_ERROR_INSUFFICIENT_RESOURCES;
    }
    memset(*ppSid, 0, dwSidBufferSize);
    wszDomainName = new WCHAR[dwDomainBufferSize];
    if (wszDomainName == NULL)  {
        return MQ_ERROR_INSUFFICIENT_RESOURCES;
    }
    memset(wszDomainName, 0, dwDomainBufferSize*sizeof(WCHAR));

    // Obtain the SID for the account name passed.
    for ( ; ; )
    {
        // Set the count variables to the buffer sizes and retrieve the SID.
        cbSid = dwSidBufferSize;
        cchDomainName = dwDomainBufferSize;
        if (LookupAccountNameW(
            NULL,            // Computer name. NULL for the local computer
            wszAccName,
            *ppSid,          // Pointer to the SID buffer. Use NULL to get the size needed,
            &cbSid,          // Size of the SID buffer needed.
            wszDomainName,   // wszDomainName,
            &cchDomainName,
            &eSidType
            ))
        {
            if (IsValidSid(*ppSid) == FALSE)
            {
                wprintf(L"The SID for %s is invalid.\n", wszAccName);
                dwErrorCode = MQ_ERROR;
            }
            break;
        }
        dwErrorCode = GetLastError();

        // Check if one of the buffers was too small.
        if (dwErrorCode == ERROR_INSUFFICIENT_BUFFER)
        {
            if (cbSid > dwSidBufferSize)
            {
                // Reallocate memory for the SID buffer.
                wprintf(L"The SID buffer was too small. It will be reallocated.\n");
                FreeSid(*ppSid);
                *ppSid = (PSID) new BYTE[cbSid];
                if (*ppSid == NULL) {
                    return MQ_ERROR_INSUFFICIENT_RESOURCES;
                }
                memset(*ppSid, 0, cbSid);
                dwSidBufferSize = cbSid;
            }
            if (cchDomainName > dwDomainBufferSize)
            {
                // Reallocate memory for the domain name buffer.
                wprintf(L"The domain name buffer was too small. It will be reallocated.\n");
                delete [] wszDomainName;
                wszDomainName = new WCHAR[cchDomainName];
                if (wszDomainName == NULL) {
                    return MQ_ERROR_INSUFFICIENT_RESOURCES;
                }
                memset(wszDomainName, 0, cchDomainName*sizeof(WCHAR));
                dwDomainBufferSize = cchDomainName;
            }
        } else {
            wprintf(L"LookupAccountNameW failed. GetLastError returned: %d\n", dwErrorCode);
            hr = HRESULT_FROM_WIN32(dwErrorCode);
            break;
        }
    }

    delete [] wszDomainName;
    return hr;
}

BOOL SetPrivilege(
    HANDLE hToken,          // access token handle
    LPCTSTR lpszPrivilege,  // name of privilege to enable/disable
    BOOL bEnablePrivilege   // to enable or disable privilege
    )
{
    TOKEN_PRIVILEGES tp;
    LUID luid;

    if ( !LookupPrivilegeValue(
        NULL,            // lookup privilege on local system
        lpszPrivilege,   // privilege to lookup
        &luid ) )        // receives LUID of privilege
    {
        printf("LookupPrivilegeValue error: %u\n", GetLastError() );
        return FALSE;
    }

    tp.PrivilegeCount = 1;
    tp.Privileges[0].Luid = luid;
    if (bEnablePrivilege)
        tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    else
        tp.Privileges[0].Attributes = 0;

    // Enable the privilege or disable all privileges.
    if ( !AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES) NULL, (PDWORD) NULL) )
    {
        printf("AdjustTokenPrivileges error: %u\n", GetLastError() );
        return FALSE;
    }

    if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
    {
        printf("The token does not have the specified privilege. \n");
        return FALSE;
    }

    return TRUE;
}


BOOL TakeOwnership(LPTSTR lpszOwnFile)
{  
    BOOL bRetval = FALSE;
    HANDLE hToken = NULL;
    PACL pACL = NULL;
    PSID pSIDEveryone = NULL;
    PSID pSIDAdmin = NULL;

    const int NUM_ACES  = 2;
    EXPLICIT_ACCESS ea[NUM_ACES];

    __try
    {
        // Specify the DACL to use.
        // Create a SID for the Everyone group.      
        SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY;
        if (!AllocateAndInitializeSid(&SIDAuthWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &pSIDEveryone))
        {
            printf("AllocateAndInitializeSid (Everyone) error %u\n", GetLastError());
            __leave;
        }

        // Create a SID for the BUILTIN\Administrators group.      
        SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY;
        if (!AllocateAndInitializeSid(&SIDAuthNT, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &pSIDAdmin))
        {
            printf("AllocateAndInitializeSid (Admin) error %u\n", GetLastError());
            __leave;
        }

        ZeroMemory(&ea, NUM_ACES * sizeof(EXPLICIT_ACCESS));

        // Set read access for Everyone.
        ea[0].grfAccessPermissions = GENERIC_READ;
        ea[0].grfAccessMode = SET_ACCESS;
        ea[0].grfInheritance = NO_INHERITANCE;
        ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
        ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
        ea[0].Trustee.ptstrName = (LPTSTR) pSIDEveryone;

        // Set full control for Administrators.
        ea[1].grfAccessPermissions = GENERIC_ALL;
        ea[1].grfAccessMode = SET_ACCESS;
        ea[1].grfInheritance = NO_INHERITANCE;
        ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
        ea[1].Trustee.TrusteeType = TRUSTEE_IS_GROUP;
        ea[1].Trustee.ptstrName = (LPTSTR) pSIDAdmin;

        if (ERROR_SUCCESS != SetEntriesInAcl(NUM_ACES, ea, NULL, &pACL))
        {
            printf("Failed SetEntriesInAcl\n");
            __leave;
        }

        // Try to modify the object's DACL.
        DWORD dwRes = SetNamedSecurityInfo(
            lpszOwnFile,                 // name of the object
            SE_FILE_OBJECT,              // type of object
            DACL_SECURITY_INFORMATION,   // change only the object's DACL
            NULL, NULL,                  // do not change owner or group
            pACL,                        // DACL specified
            NULL);                       // do not change SACL
        if (ERROR_SUCCESS == dwRes)
        {
            printf("Successfully changed DACL\n");
            bRetval = TRUE;      
            __leave;// No more processing needed.
        }
        if (dwRes != ERROR_ACCESS_DENIED)
        {
            printf("First SetNamedSecurityInfo call failed: %u\n", dwRes);
            __leave;
        }

        // If the preceding call failed because access was denied, enable the SE_TAKE_OWNERSHIP_NAME privilege, create a SID for
        // the Administrators group, take ownership of the object, and disable the privilege. Then try again to set the object's DACL.      
        if (!OpenProcessToken(GetCurrentProcess(),  TOKEN_ADJUST_PRIVILEGES, &hToken)) // Open a handle to the access token for the calling process.
        {
            printf("OpenProcessToken failed: %u\n", GetLastError());
            __leave;
        }

        if (!SetPrivilege(hToken, SE_TAKE_OWNERSHIP_NAME, TRUE)) // Enable the SE_TAKE_OWNERSHIP_NAME privilege.
        {
            printf("You must be logged on as Administrator.\n");
            __leave;
        }

        // Set the owner in the object's security descriptor.
        dwRes = SetNamedSecurityInfo(
            lpszOwnFile,                 // name of the object
            SE_FILE_OBJECT,              // type of object
            OWNER_SECURITY_INFORMATION,  // change only the object's owner
            pSIDAdmin,                   // SID of Administrator group
            NULL,
            NULL,
            NULL);
        if (dwRes != ERROR_SUCCESS)
        {
            printf("Could not set owner. Error: %u\n", dwRes);
            __leave;
        }

        if (!SetPrivilege(hToken, SE_TAKE_OWNERSHIP_NAME, FALSE)) // Disable the SE_TAKE_OWNERSHIP_NAME privilege.
        {
            printf("Failed SetPrivilege call unexpectedly.\n");
            __leave;
        }

        // Try again to modify the object's DACL,now that we are the owner.
        dwRes = SetNamedSecurityInfo(
            lpszOwnFile,                 // name of the object
            SE_FILE_OBJECT,              // type of object
            DACL_SECURITY_INFORMATION,   // change only the object's DACL
            NULL, NULL,                  // do not change owner or group
            pACL,                        // DACL specified
            NULL);                       // do not change SACL
        if (dwRes == ERROR_SUCCESS) {
            printf("Successfully changed DACL\n");
            bRetval = TRUE;
        } else {
            printf("Second SetNamedSecurityInfo call failed: %u\n", dwRes);
        }
    }
    __finally
    {
        if (pSIDAdmin)
            FreeSid(pSIDAdmin);

        if (pSIDEveryone)
            FreeSid(pSIDEveryone);

        if (pACL)
            LocalFree(pACL);

        if (hToken)
            CloseHandle(hToken);
    }

    return bRetval;
}


BOOL set_file_secure_attribute (IN LPTSTR lpszOwnFile, IN wchar_t * username, IN unsigned int attribute)
    /*
    功能:给一个文件添加一个用户(组),并给一定的权限.
    关于删除用户及删除用户(组)的某个权限,再说,应该很容易.
    */
{  
    if (!lpszOwnFile || !username) {
        return FALSE;
    }

    BOOL bRetval = FALSE;
    HANDLE hToken = NULL;
    PACL pACL = NULL;

    EXPLICIT_ACCESS ea = {0};

    __try
    {
        PSID ppSid;
        HRESULT r = GetSid(username, &ppSid) ;
        if (r != S_OK) {
            return FALSE;
        }

        ea.grfAccessPermissions = attribute;//GENERIC_READ;//GENERIC_ALL
        ea.grfAccessMode = SET_ACCESS;
        ea.grfInheritance = NO_INHERITANCE;
        ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
        ea.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;//是管理员时,这个值是TRUSTEE_IS_GROUP.不过不是这个值也成功了.
        ea.Trustee.ptstrName = (LPTSTR) ppSid;

        if (ERROR_SUCCESS != SetEntriesInAcl(1, &ea, NULL, &pACL))
        {
            printf("Failed SetEntriesInAcl\n");
            __leave;
        }

        // Try to modify the object's DACL.
        DWORD dwRes = SetNamedSecurityInfo(
            lpszOwnFile,                 // name of the object
            SE_FILE_OBJECT,              // type of object
            DACL_SECURITY_INFORMATION,   // change only the object's DACL
            NULL, NULL,                  // do not change owner or group
            pACL,                        // DACL specified
            NULL);                       // do not change SACL
        if (ERROR_SUCCESS == dwRes)
        {
            printf("Successfully changed DACL\n");
            bRetval = TRUE;      
            __leave;// No more processing needed.
        }
        if (dwRes != ERROR_ACCESS_DENIED)
        {
            printf("First SetNamedSecurityInfo call failed: %u\n", dwRes);
            __leave;
        }

        // If the preceding call failed because access was denied, enable the SE_TAKE_OWNERSHIP_NAME privilege, create a SID for
        // the Administrators group, take ownership of the object, and disable the privilege. Then try again to set the object's DACL.      
        if (!OpenProcessToken(GetCurrentProcess(),  TOKEN_ADJUST_PRIVILEGES, &hToken)) // Open a handle to the access token for the calling process.
        {
            printf("OpenProcessToken failed: %u\n", GetLastError());
            __leave;
        }

        if (!SetPrivilege(hToken, SE_TAKE_OWNERSHIP_NAME, TRUE)) // Enable the SE_TAKE_OWNERSHIP_NAME privilege.
        {
            printf("You must be logged on as Administrator.\n");
            __leave;
        }

        // Set the owner in the object's security descriptor.
        dwRes = SetNamedSecurityInfo(
            lpszOwnFile,                 // name of the object
            SE_FILE_OBJECT,              // type of object
            OWNER_SECURITY_INFORMATION,  // change only the object's owner
            ppSid,                   // SID of Administrator group
            NULL,
            NULL,
            NULL);
        if (dwRes != ERROR_SUCCESS)
        {
            printf("Could not set owner. Error: %u\n", dwRes);
            __leave;
        }

        if (!SetPrivilege(hToken, SE_TAKE_OWNERSHIP_NAME, FALSE)) // Disable the SE_TAKE_OWNERSHIP_NAME privilege.
        {
            printf("Failed SetPrivilege call unexpectedly.\n");
            __leave;
        }

        // Try again to modify the object's DACL,now that we are the owner.
        dwRes = SetNamedSecurityInfo(
            lpszOwnFile,                 // name of the object
            SE_FILE_OBJECT,              // type of object
            DACL_SECURITY_INFORMATION,   // change only the object's DACL
            NULL, NULL,                  // do not change owner or group
            pACL,                        // DACL specified
            NULL);                       // do not change SACL
        if (dwRes == ERROR_SUCCESS) {
            printf("Successfully changed DACL\n");
            bRetval = TRUE;
        } else {
            printf("Second SetNamedSecurityInfo call failed: %u\n", dwRes);
        }
    }
    __finally
    {
        if (pACL)
            LocalFree(pACL);

        if (hToken)
            CloseHandle(hToken);
    }

    return bRetval;
}


int main()
{
    BOOL B = set_file_secure_attribute (L"f:\\test.exe", L"Everyone", GENERIC_READ);
    if (!B) {
        return 0;
    }

    B = set_file_secure_attribute (L"f:\\test.exe", L"Administrators", GENERIC_ALL);
    if (!B) {
        return 0;
    }

    B = set_file_secure_attribute (L"f:\\test.exe", L"guest", GENERIC_ALL);
    if (!B) {//经测试,这个成功了,Everyone的就没有了,啥原因还是啥规矩不知道.
        return 0;
    }
   
    B = set_file_secure_attribute (L"f:\\test2.exe", L"Everyone", GENERIC_ALL);
    if (!B) {
        return 0;
    }

    //B = TakeOwnership(L"f:\\test.exe");

    return 0;
}

没有评论:

发表评论