CreateProcessAsUser() Window Stations and Desktops Program Example
When a process is started by means of the CreateProcessAsUser() function, the process will be started into a window station and desktop combination based on the value of lpDesktop in the STARTUPINFO structure parameter:
Sometimes the process may fail to start, and one of the following error messages may appear:
Error message 1:
Initialization of the dynamic library <system>\system32\user32.dll failed. The process is terminating abnormally.
Error message 2:
Initialization of the dynamic library <system>\system32\kernel32.dll failed. The process is terminating abnormally.
The error message occurs when the process that is started causes the initialization code in either the User32.dll or the Kernel32.dll file to fail because of an API call from the started process that does not have correct security access to either the targeted window station or desktop. For example, if the process that was started was trying to create a window, the process would have to have DESKTOP_CREATEWINDOW access to the desktop object. If the process has not been granted this access right, an error would occur in the User32.dll file, which would cause the system error box to appear and the process would fail to start. Note that sometimes the process may start, but fail to draw its GUI correctly. The best method to resolve these and other potential access related problems is to grant the user full access to both the targeted window station and desktop. For example, if you want the process that is started by the CreateProcessAsUser() function to be interactive, specify the following window station and desktop combination:
winsta0\default
Windows 2000 and Windows XP Issues
A new API was introduced beginning with Windows 2000, CreateProcessWithLogonW(). If the lpDesktop member of the STARTUPINFO structure is initialized to either NULL or , CreateProcessWithLogonW() implementation adds permissions for the specified user account to the inherited window station and desktop. If the application specifies a desktop in the lpDesktop member, it is the responsibility of the application to add permission for the specified user account to the specified window station and desktop. The following sample code grants the user named Johnny access to the interactive window station and desktop, winsta0\\default. Access is granted based on the logon security ID (SID) of the user Johnny. The access control entry (ACE) for each object is based on Johnny’s logon SID. The code executes the cmd.exe file. An application that runs many processes such as a scheduler service may want to remove the new ACE after the process has completed because the ACEs accumulate on the DACL of both the window station and desktop object.
All Microsoft Windows NT, Windows 2000, Windows XP Executive objects, which Window stations and Desktops belong to, have a 2K limit on Access Control Lists (ACL). SetUserObjectSecurity() returns ERROR_NOT_ENOUGH_QUOTA when this limit is reached. This 2K limit equals approximately 84 or 85 Access Control Entries (ACE). SetUserObjectSecurity() returns will return ERROR_NOT_ENOUGH_QUOTA. It is recommended that you add an ACE based on the Logon Security Identifier (SID) since this duplicates the process used by the system. Consider the following options when you experience this problem:
The lpApplicationName parameter can be NULL, in which case the executable name must be the first white space–delimited string in lpCommandLine. If the executable or path name has a space in it, there is a risk that a different executable could be run because of the way the function parses spaces. The following example is dangerous because the function will attempt to run Program.exe, if it exists, instead of MyApp.exe.
LPTSTR szCmdline[ ] = _tcsdup(TEXT(C:\\Program Files\\MyApp));
CreateProcessAsUser(hToken, NULL, szCmdline, /*...*/ );
If a malicious user were to create an application called Program.exe on a system, any program that incorrectly calls CreateProcessAsUser() using the Program Files directory will run this application instead of the intended application. To avoid this problem, do not pass NULL for lpApplicationName. If you do pass NULL for lpApplicationName, use quotation marks around the executable path in lpCommandLine, as shown in the code snippet example below.
LPTSTR szCmdline[ ] = _tcsdup(TEXT(\C:\\Program Files\\MyApp\));
CreateProcessAsUser(hToken, NULL, szCmdline, /*...*/);
Create a new empty Win32 console application project. Give a suitable project name and change the project location if needed.
Then, add the source file and give it a suitable name.
Next, add the following source code.
#include <windows.h>
#include <stdio.h>
// Constants
#define WINSTA_ALL (WINSTA_ACCESSCLIPBOARD | WINSTA_ACCESSGLOBALATOMS | \
WINSTA_CREATEDESKTOP | WINSTA_ENUMDESKTOPS | WINSTA_ENUMERATE | \
WINSTA_EXITWINDOWS |WINSTA_READATTRIBUTES | WINSTA_READSCREEN |\
WINSTA_WRITEATTRIBUTES | DELETE | READ_CONTROL | WRITE_DAC | WRITE_OWNER)
#define DESKTOP_ALL (DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW | \
DESKTOP_ENUMERATE | DESKTOP_HOOKCONTROL | \
DESKTOP_JOURNALPLAYBACK | DESKTOP_JOURNALRECORD | \
DESKTOP_READOBJECTS | DESKTOP_SWITCHDESKTOP | \
DESKTOP_WRITEOBJECTS | DELETE | READ_CONTROL | \
WRITE_DAC | WRITE_OWNER)
#define GENERIC_ACCESS (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL)
// Prototypes
BOOL ObtainSid(
HANDLE hToken, // Handle to an process access token.
PSID *psid // ptr to the buffer of the logon sid
);
void RemoveSid(
PSID *psid // ptr to the buffer of the logon sid
);
BOOL AddTheAceWindowStation(
HWINSTA hwinsta, // handle to a windowstation
PSID psid // logon sid of the process
);
BOOL AddTheAceDesktop(
HDESK hdesk, // handle to a desktop
PSID psid // logon sid of the process
);
int wmain(int argc, WCHAR **argv)
{
HANDLE hToken;
HDESK hdesk;
HWINSTA hwinsta, hwinstaold;
PROCESS_INFORMATION pi;
PSID psid;
STARTUPINFO si;
DWORD size = 0;
WCHAR szCommandLine[] = LC:\\Windows\\system32\\calc.exe;
// The following failed lol - ...0xC0000005: Access violation writing location...
// LPTSTR szCommandLine = LC:\\Windows\\system32\\calc.exe;
// attempts to log a user on to the local computer.
// obtain an access token for the user Johnny with 123 as the password
// on the local account database (the dot)
if (!LogonUser(LJohnny, L.,L123, LOGON32_LOGON_INTERACTIVE,LOGON32_PROVIDER_DEFAULT,&hToken))
{
wprintf(LLogonUser() failed, error %d!\n, GetLastError());
return 1;
}
else
wprintf(LLogonUser() is OK!\n);
// Opens the specified window station.
// obtain a handle to the interactive windowstation
hwinsta = OpenWindowStation(
Lwinsta0, // must belong to the current session.
FALSE,
READ_CONTROL | WRITE_DAC);
if (hwinsta == NULL)
{
wprintf(LOpenWindowStation() failed, error %d!\n, GetLastError());
return 1;
}
else
wprintf(LOpenWindowStation() is OK!\n);
// Retrieves a handle to the current window station for the calling process.
hwinstaold = GetProcessWindowStation();
// Assigns the specified window station to the calling process.
// set the windowstation to winsta0 so that you obtain the correct default desktop
if (!SetProcessWindowStation(hwinsta))
{
wprintf(LSetProcessWindowStation() failed, error %d!\n, GetLastError());
return 1;
}
else
wprintf(LSetProcessWindowStation() is OK!\n);
// Opens the specified desktop object.
// obtain a handle to the default desktop
hdesk = OpenDesktop(
Ldefault, // desktop must belong to the current window station.
0,
FALSE,
READ_CONTROL | WRITE_DAC | DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS);
if (hdesk == NULL)
{
wprintf(LOpenDesktop() failed, error %d!\n, GetLastError());
return 1;
}
else
wprintf(LOpenDesktop() is pretty fine!\n);
// obtain the logon sid of the user fester
if (!ObtainSid(hToken, &psid))
{
wprintf(LObtainSid() failed, error %d!\n, GetLastError());
return 1;
}
else
wprintf(LObtainSid() is OK!\n);
// add the user to interactive windowstation
if (!AddTheAceWindowStation(hwinsta, psid))
{
wprintf(LAddTheAceWindowStation() failed, error %d!\n, GetLastError());
return 1;
}
else
wprintf(LAddTheAceWindowStation() is OK!\n);
// add user to default desktop
if (!AddTheAceDesktop(hdesk, psid))
{
wprintf(LAddTheAceDesktop() failed, error %d!\n, GetLastError());
return 1;
}
else
wprintf(LAddTheAceDesktop() is OK!\n);
// free the buffer for the logon sid
wprintf(LRemoving the SID...\n);
RemoveSid(&psid);
// close the handles to the interactive windowstation and desktop
if(CloseWindowStation(hwinsta) != 0)
wprintf(Lhwinsta handle was closed successfully!\n);
else
wprintf(LFailed to close hwinsta handle, error %d\n, GetLastError());
// The CloseDesktop function will fail if any thread in the calling process
// is using the specified desktop handle or if the handle refers to
// the initial desktop of the calling process
if(CloseDesktop(hdesk) != 0)
wprintf(Lhdesk handle was closed successfully!\n);
else
wprintf(LFailed to close hdesk handle, error %d\n, GetLastError());
// initialize STARTUPINFO structure
SecureZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
// the process to be interactive
si.lpDesktop = Lwinsta0\\default;
SecureZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
// Creates a new process and its primary thread.
// The new process runs in the security context of the user represented by the specified token.
if (!CreateProcessAsUser(
hToken, // handle to the primary token that represents a user
NULL, // name of the module to be executed.
szCommandLine,
// Failed for the following - ...0xC0000005: Access violation writing location XXXXXX
// LC:\\Windows\\System32\\cmd.exe, // The command line to be executed
NULL, // A pointer to a SECURITY_ATTRIBUTES structure for the new process object
NULL, // A pointer to a SECURITY_ATTRIBUTES structure for the new thread object
FALSE, // FALSE, the handles are not inherited.
NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE, // flags that control the priority
//class and the creation of the process
NULL, // A pointer to an environment block for the new process.
NULL, // The full path to the current directory for the process
&si, // Pointer to STARTUPINFO structure
&pi)) // Pointer to PROCESS_INFORMATION structure
{
wprintf(LCreateProcessAsUser() failed, error %d!\n, GetLastError());
return 1;
}
else
wprintf(LCreateProcessAsUser() is pretty OK!\n);
// Assigns the specified window station to the calling process
SetProcessWindowStation(hwinstaold); //set it back
// close the handles
if(CloseHandle(pi.hProcess) != 0)
wprintf(Lpi.hProcess handle was closed successfully!\n);
else
wprintf(LFailed to close pi.hProcess handle! error %d\n, GetLastError());
if(CloseHandle(pi.hThread) != 0)
wprintf(Lpi.hThread handle was closed successfully!\n);
else
wprintf(LFailed to close pi.hThread handle! error %d\n, GetLastError());
return 0;
}
BOOL ObtainSid(HANDLE hToken, PSID *psid)
{
BOOL bSuccess = FALSE; // assume function will fail
DWORD dwIndex;
DWORD dwLength = 0;
TOKEN_INFORMATION_CLASS tic = TokenGroups;
PTOKEN_GROUPS ptg = NULL;
__try
{
// determine the size of the buffer
if (!GetTokenInformation(hToken,tic,(LPVOID)ptg,0,&dwLength))
{
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
ptg = (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,dwLength);
if (ptg == NULL)
{
wprintf(L Heap allocation for ptg is failed, error %d\n, GetLastError());
__leave;
}
else
wprintf(L Heap allocation for ptg is OK!\n);
}
else
__leave;
}
else
wprintf(L GetTokenInformation() is OK!\n);
// obtain the groups the access token belongs to
if (!GetTokenInformation(hToken,tic,(LPVOID)ptg,dwLength,&dwLength))
__leave;
else
wprintf(L GetTokenInformation() is pretty working!\n);
// determine which group is the logon sid
for (dwIndex = 0; dwIndex < ptg->GroupCount; dwIndex++)
{
if ((ptg->Groups[dwIndex].Attributes & SE_GROUP_LOGON_ID) == SE_GROUP_LOGON_ID)
{
// determine the length of the sid
dwLength = GetLengthSid(ptg->Groups[dwIndex].Sid);
// allocate a buffer for the logon sid
*psid = (PSID)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,dwLength);
if (*psid == NULL)
{
wprintf(L Heap allocation for psid is failed, error %d\n, GetLastError());
__leave;
}
else
wprintf(L Heap allocation for psid is OK!\n);
// obtain a copy of the logon sid
if (!CopySid(dwLength, *psid, ptg->Groups[dwIndex].Sid))
{
wprintf(L CopySid() failed, error %d\n, GetLastError());
__leave;
}
else
wprintf(L CopySid() is OK!\n);
// break out of the loop because the logon sid has been found
break;
}
}
// indicate success
bSuccess = TRUE;
}
__finally
{
// free the buffer for the token group
if (ptg != NULL)
HeapFree(GetProcessHeap(), 0, (LPVOID)ptg);
}
return bSuccess;
}
void RemoveSid(PSID *psid)
{
HeapFree(GetProcessHeap(), 0, (LPVOID)*psid);
}
BOOL AddTheAceWindowStation(HWINSTA hwinsta, PSID psid)
{
ACCESS_ALLOWED_ACE *pace;
ACL_SIZE_INFORMATION aclSizeInfo;
BOOL bDaclExist;
BOOL bDaclPresent;
BOOL bSuccess = FALSE; // assume function will fail
DWORD dwNewAclSize;
DWORD dwSidSize = 0;
DWORD dwSdSizeNeeded;
PACL pacl;
PACL pNewAcl;
PSECURITY_DESCRIPTOR psd = NULL;
PSECURITY_DESCRIPTOR psdNew = NULL;
PVOID pTempAce;
SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION;
unsigned int i;
__try
{
// obtain the dacl for the windowstation,
// retrieves security information for the specified user object.
if (!GetUserObjectSecurity(hwinsta,&si,psd,dwSidSize,&dwSdSizeNeeded))
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
psd = (PSECURITY_DESCRIPTOR)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,dwSdSizeNeeded);
if (psd == NULL)
{
wprintf(L HeapAlloc() for psd failed, error %d\n, GetLastError());
__leave;
}
else
wprintf(L Heap allocation for psd is OK!\n);
psdNew = (PSECURITY_DESCRIPTOR)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,dwSdSizeNeeded);
if (psdNew == NULL)
{
wprintf(L HeapAlloc() for psdNew failed, error %d\n, GetLastError());
__leave;
}
else
wprintf(L Heap allocation for psdNew is OK!\n);
dwSidSize = dwSdSizeNeeded;
if (!GetUserObjectSecurity(hwinsta,&si,psd,dwSidSize,&dwSdSizeNeeded))
{
wprintf(L GetUserObjectSecurity() failed, error %d\n, GetLastError());
__leave;
}
else
wprintf(L GetUserObjectSecurity() should be fine!\n);
}
else
__leave;
// create a new dacl
if (!InitializeSecurityDescriptor(psdNew,SECURITY_DESCRIPTOR_REVISION))
{
wprintf(L InitializeSecurityDescriptor() failed, error %d\n, GetLastError());
__leave;
}
else
wprintf(L InitializeSecurityDescriptor() is nothing wrong!\n);
// get dacl from the security descriptor
if (!GetSecurityDescriptorDacl(psd,&bDaclPresent,&pacl,&bDaclExist))
{
wprintf(L GetSecurityDescriptorDacl() failed, error %d\n, GetLastError());
__leave;
}
else
wprintf(L GetSecurityDescriptorDacl() is working!\n);
// initialize
ZeroMemory(&aclSizeInfo, sizeof(ACL_SIZE_INFORMATION));
aclSizeInfo.AclBytesInUse = sizeof(ACL);
// call only if the dacl is not NULL
if (pacl != NULL)
{
// get the file ACL size info
if (!GetAclInformation(
pacl,
(LPVOID)&aclSizeInfo,
sizeof(ACL_SIZE_INFORMATION),
AclSizeInformation))
{
wprintf(L GetAclInformation() failed, error %d\n, GetLastError());
__leave;
}
else
wprintf(L Woww... GetAclInformation() is working!\n);
}
// compute the size of the new acl
dwNewAclSize = aclSizeInfo.AclBytesInUse + (2 * sizeof(ACCESS_ALLOWED_ACE)) + (2 * GetLengthSid(psid)) - (2 * sizeof(DWORD));
// allocate memory for the new acl
pNewAcl = (PACL)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,dwNewAclSize);
if (pNewAcl == NULL)
{
wprintf(L Heap allocation for pNewAcl failed, error %d\n, GetLastError());
__leave;
}
else
wprintf(L Heap allocation for pNewAcl is OK!\n);
// initialize the new dacl
if (!InitializeAcl(pNewAcl, dwNewAclSize, ACL_REVISION))
{
wprintf(L InitializeAcl() failed, error %d\n, GetLastError());
__leave;
}
else
wprintf(L InitializeAcl() is pretty damn OK!\n);
// if DACL is present, copy it to a new DACL
if (bDaclPresent) // only copy if DACL was present
{
// copy the ACEs to our new ACL
if (aclSizeInfo.AceCount)
{
for (i=0; i < aclSizeInfo.AceCount; i++)
{
// get an ACE
if (!GetAce(pacl, i, &pTempAce))
{
wprintf(L GetAce() failed, error %d\n, GetLastError());
__leave;
}
else
wprintf(L GetAce() is OK!\n);
// add the ACE to the new ACL
if (!AddAce(pNewAcl,ACL_REVISION,MAXDWORD,pTempAce,((PACE_HEADER)pTempAce)->AceSize))
{
wprintf(L AddAce() failed, error %d\n, GetLastError());
__leave;
}
else
wprintf(L AddAce() is OK!\n);
}
}
}
// add the first ACE to the windowstation
pace = (ACCESS_ALLOWED_ACE *)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(psid) - sizeof(DWORD));
if (pace == NULL)
{
wprintf(L Heap allocation for pace failed, error %d\n, GetLastError());
__leave;
}
else
wprintf(L Heap allocation for pace is OK!\n);
pace->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
pace->Header.AceFlags = CONTAINER_INHERIT_ACE |INHERIT_ONLY_ACE |OBJECT_INHERIT_ACE;
pace->Header.AceSize = (WORD)(sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(psid) - sizeof(DWORD));
pace->Mask = GENERIC_ACCESS;
if (!CopySid(GetLengthSid(psid), &pace->SidStart, psid))
{
wprintf(L CopySid() failed, error %d\n, GetLastError());
__leave;
}
else
wprintf(L CopySid() is pretty fine!\n);
if (!AddAce(pNewAcl,ACL_REVISION,MAXDWORD,(LPVOID)pace,pace->Header.AceSize))
{
wprintf(L AddAce() failed, error %d\n, GetLastError());
__leave;
}
else
wprintf(L AddAce() 1 is pretty fine!\n);
// add the second ACE to the windowstation
pace->Header.AceFlags = NO_PROPAGATE_INHERIT_ACE;
pace->Mask = WINSTA_ALL;
if (!AddAce(pNewAcl,ACL_REVISION,MAXDWORD,(LPVOID)pace,pace->Header.AceSize))
{
wprintf(L AddAce() failed, error %d\n, GetLastError());
__leave;
}
else
wprintf(L AddAce() 2 is pretty fine!\n);
// set new dacl for the security descriptor
if (!SetSecurityDescriptorDacl(psdNew,TRUE,pNewAcl,FALSE))
{
wprintf(L SetSecurityDescriptorDacl() failed, error %d\n, GetLastError());
__leave;
}
else
wprintf(L SetSecurityDescriptorDacl() is pretty fine!\n);
// set the new security descriptor for the windowstation
if (!SetUserObjectSecurity(hwinsta, &si, psdNew))
{
wprintf(L SetUserObjectSecurity() failed, error %d\n, GetLastError());
__leave;
}
else
wprintf(L SetUserObjectSecurity() is pretty fine!\n);
// indicate success
bSuccess = TRUE;
}
__finally
{
// free the allocated buffers
wprintf(L Freeing up all the allocated buffers...\n);
if (pace != NULL)
HeapFree(GetProcessHeap(), 0, (LPVOID)pace);
if (pNewAcl != NULL)
HeapFree(GetProcessHeap(), 0, (LPVOID)pNewAcl);
if (psd != NULL)
HeapFree(GetProcessHeap(), 0, (LPVOID)psd);
if (psdNew != NULL)
HeapFree(GetProcessHeap(), 0, (LPVOID)psdNew);
}
return bSuccess;
}
BOOL AddTheAceDesktop(HDESK hdesk, PSID psid)
{
ACL_SIZE_INFORMATION aclSizeInfo;
BOOL bDaclExist;
BOOL bDaclPresent;
BOOL bSuccess = FALSE; // assume function will fail
DWORD dwNewAclSize;
DWORD dwSidSize = 0;
DWORD dwSdSizeNeeded;
PACL pacl;
PACL pNewAcl;
PSECURITY_DESCRIPTOR psd = NULL;
PSECURITY_DESCRIPTOR psdNew = NULL;
PVOID pTempAce;
SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION;
unsigned int i;
__try
{
// obtain the security descriptor for the desktop object
if (!GetUserObjectSecurity(hdesk,&si,psd,dwSidSize,&dwSdSizeNeeded))
{
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
psd = (PSECURITY_DESCRIPTOR)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,dwSdSizeNeeded);
if (psd == NULL)
__leave;
else
wprintf(L Heap allocation for psd is OK!\n);
psdNew = (PSECURITY_DESCRIPTOR)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,dwSdSizeNeeded);
if (psdNew == NULL)
__leave;
else
wprintf(L Heap allocation for psdNew is OK!\n);
dwSidSize = dwSdSizeNeeded;
if (!GetUserObjectSecurity(hdesk,&si,psd,dwSidSize,&dwSdSizeNeeded))
__leave;
else
wprintf(L GetUserObjectSecurity() is OK!\n);
}
else
__leave;
}
else
wprintf(L GetUserObjectSecurity() is pretty fine!\n);
// create a new security descriptor
if (!InitializeSecurityDescriptor(psdNew,SECURITY_DESCRIPTOR_REVISION))
{
wprintf(L InitializeSecurityDescriptor() failed! error %d\n, GetLastError());
__leave;
}
else
wprintf(L InitializeSecurityDescriptor() is pretty fine!\n);
// obtain the dacl from the security descriptor
if (!GetSecurityDescriptorDacl(psd,&bDaclPresent,&pacl,&bDaclExist))
{
wprintf(L GetSecurityDescriptorDacl() failed! error %d\n, GetLastError());
__leave;
}
else
wprintf(L GetSecurityDescriptorDacl() is pretty fine!\n);
// initialize
ZeroMemory(&aclSizeInfo, sizeof(ACL_SIZE_INFORMATION));
aclSizeInfo.AclBytesInUse = sizeof(ACL);
// call only if NULL dacl
if (pacl != NULL)
{
// determine the size of the ACL info
if (!GetAclInformation(pacl,(LPVOID)&aclSizeInfo,sizeof(ACL_SIZE_INFORMATION),AclSizeInformation))
{
wprintf(L GetAclInformation() failed! error %d\n, GetLastError());
__leave;
}
else
wprintf(L GetAclInformation() is pretty fine!\n);
}
// compute the size of the new acl
dwNewAclSize = aclSizeInfo.AclBytesInUse + sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(psid) - sizeof(DWORD);
// allocate buffer for the new acl
pNewAcl = (PACL)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,dwNewAclSize);
if (pNewAcl == NULL)
{
wprintf(L Heap allocation for pNewAcl failed! error %d\n, GetLastError());
__leave;
}
else
wprintf(L Heap allocation for pNewAcl is OK!\n);
// initialize the new acl
if (!InitializeAcl(pNewAcl, dwNewAclSize, ACL_REVISION))
{
wprintf(L InitializeAcl() failed! error %d\n, GetLastError());
__leave;
}
else
wprintf(L InitializeAcl() looks OK!\n);
// if DACL is present, copy it to a new DACL
if (bDaclPresent) // only copy if DACL was present
{
// copy the ACEs to our new ACL
if (aclSizeInfo.AceCount)
{
for (i=0; i < aclSizeInfo.AceCount; i++)
{
// get an ACE
if (!GetAce(pacl, i, &pTempAce))
{
wprintf(L GetAce() #%d failed! error %d\n, i, GetLastError());
__leave;
}
else
wprintf(L GetAce() #%d is pretty fine!\n, i);
// add the ACE to the new ACL
if (!AddAce(pNewAcl, ACL_REVISION, MAXDWORD, pTempAce, ((PACE_HEADER)pTempAce)->AceSize))
{
wprintf(L AddAce() #%d failed! error %d\n, i, GetLastError());
__leave;
}
else
wprintf(L AddAce() #%d looks OK!\n, i);
}
}
}
// add ace to the dacl
if (!AddAccessAllowedAce(pNewAcl,ACL_REVISION,DESKTOP_ALL,psid))
{
wprintf(L AddAccessAllowedAce() failed! error %d\n, GetLastError());
__leave;
}
else
wprintf(L AddAccessAllowedAce() looks OK!\n);
// set new dacl to the new security descriptor
if (!SetSecurityDescriptorDacl(psdNew,TRUE,pNewAcl,FALSE))
{
wprintf(L SetSecurityDescriptorDacl() failed! error %d\n, GetLastError());
__leave;
}
else
wprintf(L SetSecurityDescriptorDacl() looks OK!\n);
// set the new security descriptor for the desktop object
if (!SetUserObjectSecurity(hdesk, &si, psdNew))
{
wprintf(L SetUserObjectSecurity() failed! error %d\n, GetLastError());
__leave;
}
else
wprintf(L SetUserObjectSecurity() looks OK!\n);
// indicate success
bSuccess = TRUE;
}
__finally
{
// free buffers
wprintf(L Freeing up all the allocated buffers...\n);
if (pNewAcl != NULL)
HeapFree(GetProcessHeap(), 0, (LPVOID)pNewAcl);
if (psd != NULL)
HeapFree(GetProcessHeap(), 0, (LPVOID)psd);
if (psdNew != NULL)
HeapFree(GetProcessHeap(), 0, (LPVOID)psdNew);
}
return bSuccess;
}
Build and run the project. The following screenshot is a sample output.