//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1996. // // File: desktop.cxx // // Contents: Creation/initialization of the Scheduling Agent windowstation // and its desktop, "SAWinSta\SADesktop". This windowstation // needs to exist to run tasks when no user is logged on, or the // logged on user is different than the task-specific account. // // Classes: None. // // Functions: None. // // History: 26-Jun-96 MarkBl Created // //---------------------------------------------------------------------------- #include "..\pch\headers.hxx" #pragma hdrstop #include "debug.hxx" #include "..\inc\security.hxx" #define SA_WINDOW_STATION L"SAWinSta" #define SA_DESKTOP L"SADesktop" // // Define all access to windows objects // // From windows\gina\winlogon\secutil.c // #define DESKTOP_ALL (DESKTOP_READOBJECTS | DESKTOP_CREATEWINDOW | \ DESKTOP_CREATEMENU | DESKTOP_HOOKCONTROL | \ DESKTOP_JOURNALRECORD | DESKTOP_JOURNALPLAYBACK | \ DESKTOP_ENUMERATE | DESKTOP_WRITEOBJECTS | \ DESKTOP_SWITCHDESKTOP | STANDARD_RIGHTS_REQUIRED) #define WINSTA_ALL (WINSTA_ENUMDESKTOPS | WINSTA_READATTRIBUTES | \ WINSTA_ACCESSCLIPBOARD | WINSTA_CREATEDESKTOP | \ WINSTA_WRITEATTRIBUTES | WINSTA_ACCESSGLOBALATOMS | \ WINSTA_EXITWINDOWS | WINSTA_ENUMERATE | \ WINSTA_READSCREEN | \ STANDARD_RIGHTS_REQUIRED) #define WINSTA_ATOMS (WINSTA_ACCESSGLOBALATOMS | \ WINSTA_ACCESSCLIPBOARD ) HDESK CreateSADesktop(HWINSTA hWinSta); HWINSTA CreateSAWindowStation(void); PSID GetProcessSid(void); BOOL InitializeSAWindow(void); BOOL SetSADesktopSecurity( HDESK hDesktop, PSID pSchedAgentSid, PSID pBatchSid); BOOL SetSAWindowStationSecurity( HWINSTA hWinSta, PSID pSchedAgentSid, PSID pBatchSid); void UninitializeSAWindow(void); // Globals used in this module exclusively. // Initialized in InitializeSAWindow, closed in UnitializeSAWindow. // HWINSTA ghSAWinsta = NULL; // Handle to window station, "SAWinSta". HDESK ghSADesktop = NULL; // Handle to desktop, "SADesktop" //+--------------------------------------------------------------------------- // // Function: InitializeSAWindow // // Synopsis: Create and set security info on the windowstation\desktop, // "SAWinSta\SADesktop". This desktop exists for tasks which // run under an account different than the currently logged // on user, or when no user is logged on. Note, these tasks will // never appear on the interactive desktop. // // Arguments: None. // // Returns: TRUE -- Everything succeeded. // FALSE -- Encountered an error. // // Notes: None. // //---------------------------------------------------------------------------- BOOL InitializeSAWindow(void) { BOOL fRet = TRUE; PSID pBatchSid; PSID pSchedAgentSid; HWINSTA hWinSta = NULL; HWINSTA hServiceWinSta = NULL; HDESK hDesktop = NULL; BOOL fChangedWinSta = FALSE; // // Retrieve local system and batch account SIDs. // SID_IDENTIFIER_AUTHORITY SidAuth = SECURITY_NT_AUTHORITY; if (!AllocateAndInitializeSid(&SidAuth, 1, SECURITY_BATCH_RID, 0, 0, 0, 0, 0, 0, 0, &pBatchSid)) { schDebugOut((DEB_ERROR, "InitializeSAWindow, AllocateAndInitializeSid failed, " \ "status = 0x%lx\n", GetLastError())); return(FALSE); } if ((pSchedAgentSid = GetProcessSid()) == NULL) { fRet = FALSE; goto CleanExit; } // // Get current service window station. // hServiceWinSta = GetProcessWindowStation(); if (hServiceWinSta == NULL) { fRet = FALSE; goto CleanExit; } // // Create the window station & desktop. // if ((hWinSta = CreateSAWindowStation()) == NULL) { fRet = FALSE; goto CleanExit; } if (!SetProcessWindowStation(hWinSta)) { schDebugOut((DEB_ERROR, "InitializeSAWindow, SetProcessWindowStation failed, " \ "status = 0x%lx\n", GetLastError())); fRet = FALSE; goto CleanExit; } fChangedWinSta = TRUE; if ((hDesktop = CreateSADesktop(hWinSta)) == NULL) { fRet = FALSE; goto CleanExit; } // // Set security on the window station & desktop. // if (!SetSAWindowStationSecurity(hWinSta, pSchedAgentSid, pBatchSid)) { fRet = FALSE; goto CleanExit; } if (!SetSADesktopSecurity(hDesktop, pSchedAgentSid, pBatchSid)) { fRet = FALSE; goto CleanExit; } CleanExit: // // If we have changed the window station, switch back to service window // station. // if (fChangedWinSta) { schAssert(hServiceWinSta); if (!SetProcessWindowStation(hServiceWinSta)) { schDebugOut((DEB_ERROR, "InitializeSAWindow, SetProcessWindowStation failed, status = 0x%lx\n", GetLastError())); fRet = FALSE; } } if (pBatchSid != NULL) FreeSid(pBatchSid); if (pSchedAgentSid != NULL) LocalFree(pSchedAgentSid); if (fRet) { ghSAWinsta = hWinSta; ghSADesktop = hDesktop; } else { if (hWinSta != NULL) CloseHandle(hWinSta); if (hDesktop != NULL) CloseHandle(hDesktop); // // even though the initial NULL values should still be untouched, // we'll be extra paranoid here and pretend that gremlins may have fiddled with them // ghSAWinsta = NULL; ghSADesktop = NULL; } return(fRet); } //+--------------------------------------------------------------------------- // // Function: UninitializeSAWindow // // Synopsis: Close the global window station & desktop handles. // // Arguments: None. // // Returns: None. // // Notes: None. // //---------------------------------------------------------------------------- void UninitializeSAWindow(void) { if (ghSADesktop != NULL) { CloseDesktop(ghSADesktop); ghSADesktop = NULL; } if (ghSAWinsta != NULL) { CloseWindowStation(ghSAWinsta); ghSAWinsta = NULL; } } //+--------------------------------------------------------------------------- // // Function: GetProcessSid // // Synopsis: Obtain the SID of this process. // // Arguments: None. // // Returns: This process' sid. // NULL on failure. // // Notes: None. // //---------------------------------------------------------------------------- PSID GetProcessSid(void) { PSECURITY_DESCRIPTOR psdProcessSD = NULL; PSID pProcessSid = NULL; PSID pProcessSidTmp; DWORD cbSize; HANDLE hProcess; BOOL fOwnerDefaulted; hProcess = GetCurrentProcess(); if (hProcess == NULL) { schDebugOut((DEB_ERROR, "GetProcessSid, GetCurrentProcess failed, status = 0x%lx\n", GetLastError())); return(NULL); } // // Retrieve the buffer size necessary to retrieve this process' SD. // if (!GetKernelObjectSecurity(hProcess, OWNER_SECURITY_INFORMATION, NULL, 0, &cbSize) && GetLastError() == ERROR_INSUFFICIENT_BUFFER) { psdProcessSD = LocalAlloc(LMEM_FIXED, cbSize); if (psdProcessSD == NULL) { schDebugOut((DEB_ERROR, "GetProcessSid, process security descriptor allocation " \ "failure\n")); return(NULL); } // // Actually retrieve this process' SD. // if (!GetKernelObjectSecurity(hProcess, OWNER_SECURITY_INFORMATION, psdProcessSD, cbSize, &cbSize)) { schDebugOut((DEB_ERROR, "GetProcessSid, GetKernelObjectSecurity failed, " \ "status = 0x%lx\n", GetLastError())); goto ErrorExit; } } else { schAssert(0 && "GetKernelObjectSecurity() succeeded!"); return(NULL); } // // Retrieve the owner SID from the SD. // if (!GetSecurityDescriptorOwner(psdProcessSD, &pProcessSidTmp, &fOwnerDefaulted)) { schDebugOut((DEB_ERROR, "GetProcessSid, GetSecurityDescriptorOwner failed, " \ "status = 0x%lx\n", GetLastError())); goto ErrorExit; } // // An unnecessary check, maybe, but safe. // if (!IsValidSid(pProcessSidTmp)) { schDebugOut((DEB_ERROR, "GetProcessSid, IsValidSid failed, status = 0x%lx\n", GetLastError())); goto ErrorExit; } // // Make a copy of the SID since that returned from GetSecuritySD refers // within the security descriptor allocated above. // cbSize = GetLengthSid(pProcessSidTmp); pProcessSid = LocalAlloc(LMEM_FIXED, cbSize); if (pProcessSid == NULL) { schDebugOut((DEB_ERROR, "GetProcessSid, process SID allocation failure\n")); goto ErrorExit; } if (!CopySid(cbSize, pProcessSid, pProcessSidTmp)) { LocalFree(pProcessSid); pProcessSid = NULL; schDebugOut((DEB_ERROR, "GetProcessSid, CopySid failed, status = 0x%lx\n", GetLastError())); } ErrorExit: if (psdProcessSD != NULL) LocalFree(psdProcessSD); return(pProcessSid); } //+--------------------------------------------------------------------------- // // Function: CreateSAWindowStation // // Synopsis: Create the window station named "SAWinSta". // // Arguments: None. // // Returns: Window station handle on success. // NULL on failure. // // Notes: None. // //---------------------------------------------------------------------------- HWINSTA CreateSAWindowStation(void) { HWINSTA hWinSta; if ((hWinSta = CreateWindowStation(SA_WINDOW_STATION, NULL, MAXIMUM_ALLOWED, NULL)) == NULL) { schDebugOut((DEB_ERROR, "CreateSAWindowStation, CreateWindowStation failed, " \ "status = 0x%lx\n", GetLastError())); return(NULL); } return(hWinSta); } //+--------------------------------------------------------------------------- // // Function: CreateSADesktop // // Synopsis: Create the desktop, "SADesktop", on the window station // indicated. // // Arguments: [hWinSta] -- Window station. // // Returns: Desktop handle on success. // NULL on failure. // // Notes: None. // //---------------------------------------------------------------------------- HDESK CreateSADesktop(HWINSTA hWinSta) { HDESK hDesktop; if ((hDesktop = CreateDesktop(SA_DESKTOP, NULL, NULL, 0, MAXIMUM_ALLOWED, NULL)) == NULL) { schDebugOut((DEB_ERROR, "CreateSADesktop, CreateDesktop failed, status = 0x%lx\n", GetLastError())); return(NULL); } return(hDesktop); } //+--------------------------------------------------------------------------- // // Function: SetSAWindowStationSecurity // // Synopsis: Set permissions on the scheduling agent window station for // this process and batch users. // // Arguments: [hWinSta] -- Window station. // [pSchedAgentSid] -- Scheduling Agent process SID. // [pBatchSid] -- Batch SID. // // Returns: TRUE -- Function succeeded, // FALSE -- Otherwise. // // Notes: None. // //---------------------------------------------------------------------------- BOOL SetSAWindowStationSecurity( HWINSTA hWinSta, PSID pSchedAgentSid, PSID pBatchSid) { #define WS_ACE_COUNT 4 PACCESS_ALLOWED_ACE rgAce[WS_ACE_COUNT] = { NULL, NULL, NULL, NULL }; // Supply this to CreateSD so we // don't have to allocate memory. MYACE rgMyAce[WS_ACE_COUNT] = { { WINSTA_ALL, // Acess mask. NO_PROPAGATE_INHERIT_ACE, // Inherit flags. pSchedAgentSid }, // SID. { GENERIC_ALL, OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE, pSchedAgentSid }, { WINSTA_ALL & ~(DELETE | WRITE_DAC | WRITE_OWNER), // need to leave READ_CONTROL in this or jobs can't run NO_PROPAGATE_INHERIT_ACE, pBatchSid }, { GENERIC_READ | GENERIC_EXECUTE, INHERIT_ONLY_ACE, pBatchSid } }; schAssert(WS_ACE_COUNT == (sizeof(rgAce)/sizeof(PACCESS_ALLOWED_ACE)) && WS_ACE_COUNT == (sizeof(rgMyAce) / sizeof(MYACE))); PSECURITY_DESCRIPTOR pSecurityDescriptor; SECURITY_INFORMATION si; DWORD Status = 0; if ((pSecurityDescriptor = CreateSecurityDescriptor(WS_ACE_COUNT, rgMyAce, rgAce)) == NULL) { return(FALSE); } si = DACL_SECURITY_INFORMATION; if (!SetUserObjectSecurity(hWinSta, &si, pSecurityDescriptor)) { Status = GetLastError(); } DeleteSecurityDescriptor(pSecurityDescriptor); if (Status) { schDebugOut((DEB_ERROR, "SetSASetWindowStationSecurity, SetUserObjectSecurity failed, " \ "status = 0x%lx\n", Status)); return(FALSE); } return(TRUE); } //+--------------------------------------------------------------------------- // // Function: SetSADesktopSecurity // // Synopsis: Set permissions on the scheduling agent desktop for this // process and batch users. // // Arguments: [hDesktop] -- Desktop. // [pSchedAgentSid] -- Scheduling Agent process SID. // [pBatchSid] -- Batch SID. // // Returns: TRUE -- Function succeeded, // FALSE -- Otherwise. // // Notes: None. // //---------------------------------------------------------------------------- BOOL SetSADesktopSecurity( HDESK hDesktop, PSID pSchedAgentSid, PSID pBatchSid) { #define DT_ACE_COUNT 2 PACCESS_ALLOWED_ACE rgAce[DT_ACE_COUNT] = { NULL, NULL }; // Supply this to CreateSD so we // don't have to allocate memory. MYACE rgMyAce[DT_ACE_COUNT] = { { DESKTOP_ALL, // Acess mask. 0, // Inherit flags. pSchedAgentSid }, // SID. { DESKTOP_ALL & ~STANDARD_RIGHTS_REQUIRED, 0, pBatchSid } }; schAssert(DT_ACE_COUNT == (sizeof(rgAce)/sizeof(PACCESS_ALLOWED_ACE)) && DT_ACE_COUNT == (sizeof(rgMyAce) / sizeof(MYACE))); PSECURITY_DESCRIPTOR pSecurityDescriptor; SECURITY_INFORMATION si; DWORD Status = 0; if ((pSecurityDescriptor = CreateSecurityDescriptor(DT_ACE_COUNT, rgMyAce, rgAce)) == NULL) { return(FALSE); } si = DACL_SECURITY_INFORMATION; if (!SetUserObjectSecurity(hDesktop, &si, pSecurityDescriptor)) { Status = GetLastError(); } DeleteSecurityDescriptor(pSecurityDescriptor); if (Status) { schDebugOut((DEB_ERROR, "SetSADesktopSecurity, SetUserObjectSecurity failed, " \ "status = 0x%lx\n", Status)); return(FALSE); } return(TRUE); }