/*=================================================================== Microsoft IIS Microsoft Confidential. Copyright 1996-1997 Microsoft Corporation. All Rights Reserved. Component: Server object File: NTSec.cxx Owner: AndrewS This file contains code related to NT security on WinSta's and Desktops ===================================================================*/ #include #include #include #include #include #include #include "ntsec.h" // Globals HWINSTA ghWinSta = NULL; HWINSTA ghWinStaPrev = NULL; HDESK ghDesktop = NULL; HDESK ghdeskPrev = NULL; HRESULT InitOleSecurity(BOOL); /*=================================================================== InitDesktopWinsta Create a desktop and a winstation for IIS to use Parameters: Returns: HRESULT NOERROR on success Side effects Sets global variables ===================================================================*/ HRESULT InitDesktopWinsta( BOOL fAllowError ) { HRESULT hr = NOERROR; DWORD err; HWINSTA hWinSta = NULL; HDESK hDesktop = NULL; OSVERSIONINFO osInfo; BOOL fWinNT = FALSE; osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if ( GetVersionEx( &osInfo ) ) { fWinNT = (osInfo.dwPlatformId == VER_PLATFORM_WIN32_NT); } // Only applies to NT if ( !fWinNT ) return(NOERROR); // Save our old window station so we can restore it later ghWinStaPrev = GetProcessWindowStation(); if (ghWinStaPrev == NULL) goto LErr; // Create a winsta for IIS to use if ((hWinSta = CreateWindowStation(SZ_IIS_WINSTA, NULL, WINSTA_ALL, NULL)) == NULL) { if ( !fAllowError ) { goto LErr; } } else { // Set this as IIS's window station if (!SetProcessWindowStation(hWinSta)) goto LErr; } // Save the old desktop because we might need it later for an obscure error condition if ((ghdeskPrev = GetThreadDesktop(GetCurrentThreadId())) == NULL) { goto LErr; } // Create a desktop for IIS to use if ((hDesktop = CreateDesktop(SZ_IIS_DESKTOP, NULL, NULL, 0, DESKTOP_ALL, NULL)) == NULL) { if ( !fAllowError ) { goto LErr; } } // store these handles in the globals ghWinSta = hWinSta; ghDesktop = hDesktop; // Now initialize Ole security hr = InitOleSecurity(fAllowError); return(hr); LErr: if (ghWinStaPrev != NULL) SetProcessWindowStation(ghWinStaPrev); if (hWinSta != NULL) CloseWindowStation(hWinSta); if (hDesktop != NULL) CloseDesktop(hDesktop); err = GetLastError(); hr = HRESULT_FROM_WIN32(err); return(hr); } /*=================================================================== UnInitDesktopWinsta Destroy the IIS desktop and winstation Parameters: None Returns: Nothing Side effects Sets global variables ===================================================================*/ VOID UnInitDesktopWinsta() { BOOL fClosed; if (ghWinSta != NULL) { // Set winsta back to the old winsta so we can close the new one fClosed = SetProcessWindowStation(ghWinStaPrev); DBG_ASSERT(fClosed); fClosed = CloseWindowStation(ghWinSta); DBG_ASSERT(fClosed); ghWinSta = NULL; } if (ghDesktop != NULL) { BOOL fRetried = FALSE; LRetry: DBG_ASSERT(ghDesktop != NULL); fClosed = CloseDesktop(ghDesktop); // If this fails, it probably means that we are in the obscure case where // IIS's CacheExtensions registry setting is 0. In this case, we are shutting // down in a worker thread. This worker thread is using the desktop, so // it cant be closed. In this case, attempt to set the desktop back to the // original IIS desktop, and then retry closing the desktop. Only retry once. if (!fClosed && !fRetried) { fRetried = TRUE; if (!SetThreadDesktop(ghdeskPrev)) DBG_ASSERT(FALSE); goto LRetry; } DBG_ASSERT(fClosed); ghDesktop = NULL; } return; } /*=================================================================== SetDesktop Set the desktop for the calling thread Parameters: None Returns: NOERROR on success Side effects: Sets desktop ===================================================================*/ HRESULT SetDesktop( BOOL fAllowError ) { DWORD err; if (!SetThreadDesktop(ghDesktop)) goto LErr; return(NOERROR); LErr: if ( !fAllowError ) { DBG_ASSERT(FALSE); } err = GetLastError(); return(HRESULT_FROM_WIN32(err)); } /*=================================================================== InitOleSecurity Setup for and call CoInitializeSecurity. This will avoid problems with DCOM security on sites that have no default security. Parameters: None Returns: Retail -- Always returns NOERROR, failures are ignored. We dont want to have a failure of setting up security stop IIS from running at all. Debug -- DBG_ASSERTs on error and returns error code Side effects: Sets desktop ===================================================================*/ HRESULT InitOleSecurity( BOOL fAllowError ) { HRESULT hr = NOERROR; BOOL fDoCoUninit = TRUE; DWORD err; SECURITY_DESCRIPTOR SecurityDesc; SID NullSid = { SID_REVISION, 1, SECURITY_NULL_SID_AUTHORITY, SECURITY_NULL_RID }; HDESK hdeskSave = NULL; /* * We need to set up a security descriptor with an empty ACL so that * we can CoInitializeSecurity but not give everyone access to the server. */ if (!InitializeSecurityDescriptor(&SecurityDesc, SECURITY_DESCRIPTOR_REVISION)) goto LErr; ACL Acl; // Initialize a new ACL. if (!InitializeAcl(&Acl, sizeof(ACL), ACL_REVISION2)) goto LErr; // Add new ACL to the security descriptor. if (!SetSecurityDescriptorDacl( &SecurityDesc, TRUE, &Acl, FALSE )) goto LErr; if (!SetSecurityDescriptorOwner(&SecurityDesc, &NullSid, FALSE)) goto LErr; if (!SetSecurityDescriptorGroup(&SecurityDesc, &NullSid, FALSE)) goto LErr; /* * This work must be done on the desktop that our threads are going to use. * However, we are currently running on IIS's thread, and we dont want to * whack their desktop. So, set to our desktop, do the CoInitializeSecurity, * then set the old desktop back again. Ole will cache the desktop that * was set when this CoInitSec was done. */ if (FAILED(hr = SetDesktop(fAllowError))) { goto LErr; } hr = CoInitialize(NULL); if( FAILED(hr) ) { fDoCoUninit = FALSE; } hr = CoInitializeSecurity( NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_CONNECT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_DYNAMIC_CLOAKING, NULL ); if( FAILED(hr) ) { DBGERROR(( DBG_CONTEXT, "CoInitializeSecurity failed running with default " "DCOM security settings, hr=%8x\n", hr )); } if( fDoCoUninit ) { CoUninitialize(); } // Set the desktop back to what IIS expected it to be if (!SetThreadDesktop(ghdeskPrev)) { // Nothing we can do if this fails DBG_ASSERT(FALSE); } // // This may fire if CoInitializeSecurity fails. So it is probably // overactive we would have let the CoInitializeSecurity call fail // in the past, before some PREFIX changes. // DBG_ASSERT(SUCCEEDED(hr)); return(hr); LErr: DBG_ASSERT(FALSE); if (SUCCEEDED(hr)) { err = GetLastError(); hr = HRESULT_FROM_WIN32(err); } #ifdef DEBUG return(hr); #else return(NOERROR); #endif }