Window Stations and Desktops 5

 

 

 

 

 

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:

 

  1. If a window station and desktop combination is specified in the lpDesktop member, the system will try to start the process into that window station and desktop.
  2. If the lpDesktop member is initialized to NULL, the system will try to use the same window station and desktop as the calling process if the system is associated with the interactive window station.
  3. If the lpDesktop member is not initialized to NULL, the system will create a new window station and desktop that you cannot see.
  4. If the system is initialized with the empty string, "", it will either create a new window station and desktop that you cannot see, or if one has been created by means of a prior call by using the same access token, the existing window station and desktop will be used.

 

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:

 

  1. If you are launching many processes running in the same security context or logon session, you might want to add one ACE versus an ACE for every process.
  2. If you can keep track of when the process dies, you should remove the ACE when the process has terminated.
  3. If you cannot track when the process dies, there are several procedures that you can use to remove any unnecessary ACEs. You can enumerate processes, read the Logon Security Identifier (SID) or User SID from the process token, and compare one of them to the ACEs stored in the DACL for the window station and desktop objects. This depends on which ACE you used to secure the object. Remove any ACEs for processes that are no longer running on the system. NOTE: there might be other processes that are adding ACEs to the objects.
  4. If you are launching many processes, you might want to add an ACE based on the processes logon type. For example, this could be either the Interactive or Batch SID. You would not have to add any additional ACEs for processes with the same logon type.

 

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.

 

CreateProcessAsUser() Window Stations and Desktops Program Example: Creating new empty Win32 console mode application project in VC++

 

Then, add the source file and give it a suitable name.

 

CreateProcessAsUser() Window Stations and Desktops Program Example: Adding new  C++ source file

 

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[] = L"C:\\Windows\\system32\\calc.exe";

      // The following failed lol - ...0xC0000005: Access violation writing location...

      //          LPTSTR szCommandLine = L"C:\\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(L"Johnny", L".",L"123", LOGON32_LOGON_INTERACTIVE,LOGON32_PROVIDER_DEFAULT,&hToken))

      {

            wprintf(L"LogonUser() failed, error %d!\n", GetLastError());

            return 1;

      }

      else

            wprintf(L"LogonUser() is OK!\n");

 

      // Opens the specified window station.

      // obtain a handle to the interactive windowstation

      hwinsta = OpenWindowStation(

            L"winsta0", // must belong to the current session.

            FALSE,

            READ_CONTROL | WRITE_DAC);

     

      if (hwinsta == NULL)

      {

            wprintf(L"OpenWindowStation() failed, error %d!\n", GetLastError());

            return 1;

      }

      else

            wprintf(L"OpenWindowStation() 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(L"SetProcessWindowStation() failed, error %d!\n", GetLastError());

            return 1;

      }

      else

            wprintf(L"SetProcessWindowStation() is OK!\n");

     

      // Opens the specified desktop object.

      // obtain a handle to the "default" desktop

      hdesk = OpenDesktop(

            L"default", // desktop must belong to the current window station.

            0,

            FALSE,

            READ_CONTROL | WRITE_DAC | DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS);

     

      if (hdesk == NULL)

      {

            wprintf(L"OpenDesktop() failed, error %d!\n", GetLastError());

            return 1;

      }

      else

            wprintf(L"OpenDesktop() is pretty fine!\n");

     

      // obtain the logon sid of the user fester

      if (!ObtainSid(hToken, &psid))

      {

            wprintf(L"ObtainSid() failed, error %d!\n", GetLastError());

            return 1;

      }

      else

            wprintf(L"ObtainSid() is OK!\n");

     

      // add the user to interactive windowstation

      if (!AddTheAceWindowStation(hwinsta, psid))

      {

            wprintf(L"AddTheAceWindowStation() failed, error %d!\n", GetLastError());

            return 1;

      }

      else

            wprintf(L"AddTheAceWindowStation() is OK!\n");

     

      // add user to "default" desktop

      if (!AddTheAceDesktop(hdesk, psid))

      {

            wprintf(L"AddTheAceDesktop() failed, error %d!\n", GetLastError());

            return 1;

      }

      else

            wprintf(L"AddTheAceDesktop() is OK!\n");

      // free the buffer for the logon sid

      wprintf(L"Removing the SID...\n");

      RemoveSid(&psid);

     

      // close the handles to the interactive windowstation and desktop

      if(CloseWindowStation(hwinsta) != 0)

            wprintf(L"hwinsta handle was closed successfully!\n");

      else

            wprintf(L"Failed 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(L"hdesk handle was closed successfully!\n");

      else

            wprintf(L"Failed 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 = L"winsta0\\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

            //          L"C:\\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(L"CreateProcessAsUser() failed, error %d!\n", GetLastError());       

            return 1;

      }

      else

            wprintf(L"CreateProcessAsUser() 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(L"pi.hProcess handle was closed successfully!\n");

      else

            wprintf(L"Failed to close pi.hProcess handle! error %d\n", GetLastError());

      if(CloseHandle(pi.hThread) != 0)

            wprintf(L"pi.hThread handle was closed successfully!\n");

      else

            wprintf(L"Failed 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.

 

CreateProcessAsUser() Window Stations and Desktops Program Example: A sample console program output

 

CreateProcessAsUser() Window Stations and Desktops Program Example: Another sample program output

 

 

 

 

< Window Station and Desktop 4 | Window Station and Desktop | Win32 Programming | Window Station and Desktop 6 >