//+------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1997. // // File: launch.cxx // // Contents: // // History: ?-??-?? ??? Created // 6-17-99 a-sergiv Added event log filtering // //-------------------------------------------------------------------------- #include "act.hxx" #include // For CreateProcessInternalW extern "C" { #include } #include "execclt.hxx" const ULONG MAX_SERVICE_ARGS = 16; const WCHAR REGEVENT_PREFIX[] = L"RPCSS_REGEVENT:"; const DWORD REGEVENT_PREFIX_STRLEN = sizeof(REGEVENT_PREFIX) / sizeof(WCHAR) - 1; const WCHAR INITEVENT_PREFIX[] = L"RPCSS_INITEVENT:"; const DWORD INITEVENT_PREFIX_STRLEN = sizeof(INITEVENT_PREFIX) / sizeof(WCHAR) - 1; HRESULT CClsidData::GetAAASaferToken( IN CToken *pClientToken, OUT HANDLE *pTokenOut ) /*++ Routine Description: Get the token that will be used in an Activate As Activator launch. This token is the more restricted of the incoming token and the configured safer level. Arguments: pClientToken - token of the user doing the activation pTokenOut - out parameter that will recieve the handle to use in the activation. Return Value: S_OK: Everything went fine. The caller owns a reference on pTokenOut and must close it. S_FALSE: Everything went fine. The caller does not own a reference on pToken out and does not need to close it. Anything else: An error occured. --*/ { HANDLE hSaferToken = NULL; HRESULT hr = S_OK; BOOL bStatus = TRUE; *pTokenOut = NULL; ASSERT(SaferLevel() && "Called GetAAASaferToken with SAFER disabled!"); if (!SaferLevel()) return E_UNEXPECTED; // Get the safer token for this configuration. bStatus = SaferComputeTokenFromLevel(SaferLevel(), pClientToken->GetToken(), &hSaferToken, 0, NULL); if (bStatus) { hr = pClientToken->CompareSaferLevels(hSaferToken); if (hr == S_OK) { CloseHandle(hSaferToken); hSaferToken = pClientToken->GetToken(); // Shared reference, return S_FALSE. hr = S_FALSE; } else { hr = S_OK; } } else { hr = HRESULT_FROM_WIN32(GetLastError()); } *pTokenOut = hSaferToken; return hr; } HRESULT CClsidData::LaunchActivatorServer( IN CToken * pClientToken, IN WCHAR * pEnvBlock, IN DWORD EnvBlockLength, IN BOOL fIsRemoteActivation, IN BOOL fClientImpersonating, IN WCHAR* pwszWinstaDesktop, IN DWORD clsctx, OUT HANDLE * phProcess, OUT DWORD * pdwProcessId ) { WCHAR * pwszCommandLine; WCHAR * pFinalEnvBlock; STARTUPINFO StartupInfo; PROCESS_INFORMATION ProcessInfo; SECURITY_ATTRIBUTES saProcess; PSECURITY_DESCRIPTOR psdNewProcessSD; HRESULT hr; DWORD CreateFlags; BOOL bStatus = FALSE; ULONG SessionId = 0; HANDLE hSaferToken = NULL; BOOL bCloseSaferToken = TRUE; *phProcess = NULL; *pdwProcessId = 0; if ( ! pClientToken ) return (E_ACCESSDENIED); pFinalEnvBlock = NULL; StartupInfo.cb = sizeof(StartupInfo); StartupInfo.lpReserved = NULL; // Choose desktop for new server: // client remote -> system chooses desktop // client local, not impersonating -> we pick client's desktop // client local, impersonating -> system chooses desktop StartupInfo.lpDesktop = (fIsRemoteActivation || fClientImpersonating) ? L"" : pwszWinstaDesktop; StartupInfo.lpTitle = (SERVERTYPE_SURROGATE == _ServerType) ? NULL : _pwszServer; StartupInfo.dwX = 40; StartupInfo.dwY = 40; StartupInfo.dwXSize = 80; StartupInfo.dwYSize = 40; StartupInfo.dwFlags = 0; StartupInfo.wShowWindow = SW_SHOWNORMAL; StartupInfo.cbReserved2 = 0; StartupInfo.lpReserved2 = NULL; ProcessInfo.hThread = 0; ProcessInfo.hProcess = 0; ProcessInfo.dwProcessId = 0; hr = GetLaunchCommandLine( &pwszCommandLine ); if ( hr != S_OK ) return (hr); if ( pEnvBlock ) { hr = AddAppPathsToEnv( pEnvBlock, EnvBlockLength, &pFinalEnvBlock ); if ( hr != S_OK ) { PrivMemFree( pwszCommandLine ); return (hr); } } CreateFlags = CREATE_NEW_CONSOLE; if ( pFinalEnvBlock ) CreateFlags |= CREATE_UNICODE_ENVIRONMENT; CAccessInfo AccessInfo( pClientToken->GetSid() ); // // Apply configured safer restrictions to the token we're using to launch. // SAFER might not be enabled at all, in which case we don't need to do this. // if ( gbSAFERAAAChecksEnabled && SaferLevel() ) { hr = GetAAASaferToken( pClientToken, &hSaferToken ); if ( FAILED(hr) ) goto LaunchServerEnd; if ( hr == S_FALSE ) { // GetAAASaferToken has returned a shared reference // to pClientToken. bCloseSaferToken = FALSE; hr = S_OK; } else bCloseSaferToken = TRUE; } else { hSaferToken = pClientToken->GetToken(); bCloseSaferToken = FALSE; } // // This should never fail here, but if it did that would be a really, // really bad security breach, so check it anyway. // if ( ! ImpersonateLoggedOnUser( hSaferToken ) ) { hr = E_ACCESSDENIED; goto LaunchServerEnd; } // // Initialize process security info (SDs). We need both SIDs to // do this, so here is the 1st time we can. We Delete the SD right // after the CreateProcess call, no matter what happens. // psdNewProcessSD = AccessInfo.IdentifyAccess( FALSE, PROCESS_ALL_ACCESS, PROCESS_SET_INFORMATION | // Allow primary token to be set PROCESS_TERMINATE | SYNCHRONIZE // Allow screen-saver control ); if ( ! psdNewProcessSD ) { RevertToSelf(); hr = E_OUTOFMEMORY; goto LaunchServerEnd; } saProcess.nLength = sizeof(SECURITY_ATTRIBUTES); saProcess.lpSecurityDescriptor = psdNewProcessSD; saProcess.bInheritHandle = FALSE; SessionId = fIsRemoteActivation ? 0 : pClientToken->GetSessionId(); if( SessionId != 0 ) { // // We must send the request to the remote WinStation // of the requestor // // NOTE: The current WinStationCreateProcessW() does not use // the supplied security descriptor, but creates the // process under the account of the logged on user. // // We do not stuff the security descriptor, so clear the suspend flag #if DBGX CairoleDebugOut((DEB_TRACE, "SCM: Sending CreateProcess to SessionId %d\n",SessionId)); #endif // Non-zero sessions have only one winstation/desktop which is // the default one. We will ignore the winstation/desktop passed // in and use the default one. // review: Figure this out TarunA 05/07/99 //StartupInfo.lpDesktop = L"WinSta0\\Default"; // jsimmons 4/6/00 -- note that if the client was impersonating, then we won't // launch the server under the correct identity. More work needed to determine // if we can fully support this. // // Stop impersonating before doing the WinStationCreateProcess. // The remote winstation exec thread will launch the app under // the users context. We must not be impersonating because this // call only lets SYSTEM request the remote execute. // RevertToSelf(); HANDLE hDuplicate = NULL; // We need to pass in the SAFER blessed token to TS so that the // server can use that token // TS code will call CreateProcessAsUser, so we need to get a primary token if (DuplicateTokenForSessionUse(hSaferToken, &hDuplicate)) { if (bCloseSaferToken) { CloseHandle(hSaferToken); } hSaferToken = hDuplicate; bCloseSaferToken = TRUE; bStatus = CreateRemoteSessionProcess( SessionId, hSaferToken, FALSE, // Run as Logged on USER ServerExecutable(), // application name pwszCommandLine, // command line &saProcess, // process sec attributes NULL, // default thread sec attributes // (this was &saThread, but isn't needed) FALSE, // dont inherit handles CreateFlags, // creation flags pFinalEnvBlock, // use same enviroment block as the client NULL, // use same directory &StartupInfo, // startup info &ProcessInfo // proc info returned ); } } else { HANDLE hPrimary = NULL; if (DuplicateTokenAsPrimary(hSaferToken, pClientToken->GetSid(), &hPrimary)) { if (bCloseSaferToken) { CloseHandle(hSaferToken); } hSaferToken = hPrimary; bCloseSaferToken = TRUE; // // Do the exec while impersonating so the file access gets ACL // checked correctly. // // bStatus = CreateProcessAsUser( hSaferToken, ServerExecutable(), pwszCommandLine, &saProcess, NULL, FALSE, CreateFlags, pFinalEnvBlock, NULL, &StartupInfo, &ProcessInfo); } RevertToSelf(); } if ( ! bStatus ) { hr = HRESULT_FROM_WIN32( GetLastError() ); LogServerStartError( &_Clsid, clsctx, pClientToken, pwszCommandLine ); goto LaunchServerEnd; } LaunchServerEnd: if ( pFinalEnvBlock && pFinalEnvBlock != pEnvBlock ) PrivMemFree( pFinalEnvBlock ); if ( ProcessInfo.hThread ) CloseHandle( ProcessInfo.hThread ); if ( ProcessInfo.hProcess && ! bStatus ) { CloseHandle( ProcessInfo.hProcess ); ProcessInfo.hProcess = 0; } if ( hSaferToken && bCloseSaferToken ) { CloseHandle( hSaferToken ); } *phProcess = ProcessInfo.hProcess; *pdwProcessId = ProcessInfo.dwProcessId; PrivMemFree( pwszCommandLine ); return (hr); } //+------------------------------------------------------------------------- // // LaunchRunAsServer // //-------------------------------------------------------------------------- HRESULT CClsidData::LaunchRunAsServer( IN CToken * pClientToken, IN BOOL fIsRemoteActivation, IN ActivationPropertiesIn *pActIn, IN DWORD clsctx, OUT HANDLE * phProcess, OUT DWORD * pdwProcessId, OUT void** ppvRunAsHandle ) { WCHAR * pwszCommandLine; STARTUPINFO StartupInfo; PROCESS_INFORMATION ProcessInfo = {0}; HANDLE hToken; SECURITY_ATTRIBUTES saProcess; PSECURITY_DESCRIPTOR psdNewProcessSD; PSID psidUserSid; HRESULT hr; BOOL bStatus = FALSE; ULONG ulSessionId; BOOL bFromRunAsCache = FALSE; hr = GetLaunchCommandLine( &pwszCommandLine ); if ( hr != S_OK ) return (hr); *phProcess = NULL; *pdwProcessId = 0; hToken = NULL; bStatus = FALSE; StartupInfo.cb = sizeof(STARTUPINFO); StartupInfo.lpReserved = NULL; StartupInfo.lpDesktop = NULL; StartupInfo.lpTitle = (SERVERTYPE_SURROGATE == _ServerType) ? NULL : _pwszServer; StartupInfo.dwFlags = 0; StartupInfo.cbReserved2 = 0; StartupInfo.lpReserved2 = NULL; ulSessionId = 0; if( IsInteractiveUser() ) { if (!fIsRemoteActivation) { // This code seems to be saying, "if the client is local then I // should always be able to impersonate him". Which is true under // normal circumstances, but we have seen a case (stress machine // shutdowns) where the client is local but came in un-authenticated. if (!pClientToken) return E_ACCESSDENIED; if ( !ImpersonateLoggedOnUser( pClientToken->GetToken() ) ) { PrivMemFree(pwszCommandLine); return E_ACCESSDENIED; } RevertToSelf(); } ASSERT(pActIn); LONG lSessIdTemp; // Query for incoming session GetSessionIDFromActParams(pActIn, &lSessIdTemp); if (lSessIdTemp != INVALID_SESSION_ID) { ulSessionId = lSessIdTemp; } // Right now force all complus to // session 0. Session based activation // is still ill defined for complus // servers. if (_ServerType == SERVERTYPE_COMPLUS) { ulSessionId = 0; } hToken = GetUserTokenForSession(ulSessionId); } else { hToken = GetRunAsToken( clsctx, AppidString(), RunAsDomain(), RunAsUser(), TRUE); if (hToken) { hr = RunAsGetTokenElem(&hToken, ppvRunAsHandle); if (SUCCEEDED(hr)) bFromRunAsCache = TRUE; else { ASSERT((*ppvRunAsHandle == NULL) && "RunAsGetTokenElem failed but *ppvRunAsHandle is non-NULL"); PrivMemFree( pwszCommandLine ); CloseHandle(hToken); return hr; } } } if ( ! hToken ) { PrivMemFree( pwszCommandLine ); return (CO_E_RUNAS_LOGON_FAILURE); } psdNewProcessSD = 0; psidUserSid = GetUserSid(hToken); CAccessInfo AccessInfo(psidUserSid); // We have to get past the CAccessInfo before we can use a goto. if ( psidUserSid ) { psdNewProcessSD = AccessInfo.IdentifyAccess( FALSE, PROCESS_ALL_ACCESS, PROCESS_SET_INFORMATION | // Allow primary token to be set PROCESS_TERMINATE | SYNCHRONIZE // Allow screen-saver control ); } if ( ! psdNewProcessSD ) { hr = E_OUTOFMEMORY; goto LaunchRunAsServerEnd; } saProcess.nLength = sizeof(SECURITY_ATTRIBUTES); saProcess.lpSecurityDescriptor = psdNewProcessSD; saProcess.bInheritHandle = FALSE; { // // Get the environment block of the user // LPVOID lpEnvBlock = NULL; bStatus = CreateEnvironmentBlock(&lpEnvBlock, hToken, FALSE); HANDLE hSaferToken = NULL; if(bStatus && SaferLevel()) { bStatus = SaferComputeTokenFromLevel(SaferLevel(), hToken, &hSaferToken, 0, NULL); } else { hSaferToken = hToken; } if (bStatus && (ulSessionId != 0)) { bStatus = SetTokenInformation(hSaferToken, TokenSessionId, &ulSessionId, sizeof(ulSessionId)); } if(bStatus) { // // This allows the process create to work with paths to remote machines. // (void) ImpersonateLoggedOnUser( hSaferToken ); bStatus = CreateProcessAsUser(hSaferToken, ServerExecutable(), pwszCommandLine, &saProcess, NULL, FALSE, CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT, lpEnvBlock, NULL, &StartupInfo, &ProcessInfo); (void) RevertToSelf(); } // // Free the environment block buffer // if (lpEnvBlock) DestroyEnvironmentBlock(lpEnvBlock); if (hSaferToken && SaferLevel()) CloseHandle(hSaferToken); } if ( ! bStatus ) { hr = HRESULT_FROM_WIN32( GetLastError() ); LogRunAsServerStartError( &_Clsid, clsctx, pClientToken, pwszCommandLine, RunAsUser(), RunAsDomain() ); goto LaunchRunAsServerEnd; } *phProcess = ProcessInfo.hProcess; *pdwProcessId = ProcessInfo.dwProcessId; NtClose( ProcessInfo.hThread ); LaunchRunAsServerEnd: if ( hToken ) { NtClose( hToken ); } if ( psidUserSid ) { PrivMemFree(psidUserSid); } PrivMemFree( pwszCommandLine ); if (!bFromRunAsCache) *ppvRunAsHandle = NULL; else if (!SUCCEEDED(hr)) { RunAsRelease(*ppvRunAsHandle); *ppvRunAsHandle = NULL; } return (hr); } //+------------------------------------------------------------------------- // // Member: LaunchService // //-------------------------------------------------------------------------- HRESULT CClsidData::LaunchService( IN CToken * pClientToken, IN DWORD clsctx, OUT SC_HANDLE * phService ) { WCHAR *pwszArgs = NULL; ULONG cArgs = 0; WCHAR *apwszArgs[MAX_SERVICE_ARGS]; BOOL bStatus; HRESULT hr; ASSERT(g_hServiceController); *phService = OpenService( g_hServiceController, _pAppid->Service(), GENERIC_EXECUTE | GENERIC_READ ); if ( ! *phService ) return (HRESULT_FROM_WIN32( GetLastError() )); // Formulate the arguments (if any) if ( ServiceArgs() ) { UINT k = 0; // Make a copy of the service arguments pwszArgs = (WCHAR *) PrivMemAlloc( (lstrlenW(ServiceArgs()) + 1) * sizeof(WCHAR)); if ( pwszArgs == NULL ) { CloseServiceHandle(*phService); *phService = 0; return (E_OUTOFMEMORY); } lstrcpyW(pwszArgs, ServiceArgs()); // Scan the arguments do { // Scan to the next non-whitespace character while ( pwszArgs[k] && (pwszArgs[k] == L' ' || pwszArgs[k] == L'\t') ) { k++; } // Store the next argument if ( pwszArgs[k] ) { apwszArgs[cArgs++] = &pwszArgs[k]; } // Scan to the next whitespace char while ( pwszArgs[k] && pwszArgs[k] != L' ' && pwszArgs[k] != L'\t' ) { k++; } // Null terminate the previous argument if ( pwszArgs[k] ) { pwszArgs[k++] = L'\0'; } } while ( pwszArgs[k] ); } bStatus = StartService( *phService, cArgs, cArgs > 0 ? (LPCTSTR *) apwszArgs : NULL); PrivMemFree(pwszArgs); if ( bStatus ) return (S_OK); DWORD dwErr = GetLastError(); hr = HRESULT_FROM_WIN32( dwErr ); if ( dwErr == ERROR_SERVICE_ALREADY_RUNNING ) return (hr); CairoleDebugOut((DEB_ERROR, "StartService %ws failed, error = %#x\n",_pAppid->Service(),GetLastError())); CloseServiceHandle(*phService); *phService = 0; LogServiceStartError( &_Clsid, clsctx, pClientToken, _pAppid->Service(), ServiceArgs(), dwErr ); return (hr); } //+------------------------------------------------------------------------- // // LaunchAllowed // //-------------------------------------------------------------------------- BOOL CClsidData::LaunchAllowed( IN CToken * pClientToken, IN DWORD clsctx ) { BOOL bStatus; ASSERT(pClientToken); #if DBG WCHAR wszUser[MAX_PATH]; ULONG cchSize = MAX_PATH; pClientToken->Impersonate(); GetUserName( wszUser, &cchSize ); pClientToken->Revert(); CairoleDebugOut((DEB_TRACE, "RPCSS : CClsidData::LaunchAllowed on %ws\n", wszUser)); #endif if ( LaunchPermission() ) bStatus = CheckForAccess( pClientToken, LaunchPermission() ); else { CSecDescriptor* pSD = GetDefaultLaunchPermissions(); if (pSD) { bStatus = CheckForAccess( pClientToken, pSD->GetSD() ); pSD->DecRefCount(); } else bStatus = FALSE; } if ( ! bStatus ) { LogLaunchAccessFailed( &_Clsid, clsctx, pClientToken, 0 == LaunchPermission() ); } return (bStatus); } HRESULT CClsidData::GetLaunchCommandLine( OUT WCHAR ** ppwszCommandLine ) { DWORD AllocBytes; *ppwszCommandLine = 0; if ( (SERVERTYPE_EXE16 == _ServerType) || (SERVERTYPE_EXE32 == _ServerType) ) { AllocBytes = ( 1 + lstrlenW( L"-Embedding" ) + 1 + lstrlenW( _pwszServer ) ) * sizeof(WCHAR); *ppwszCommandLine = (WCHAR *) PrivMemAlloc( AllocBytes ); if ( *ppwszCommandLine != NULL ) { lstrcpyW( *ppwszCommandLine, _pwszServer ); lstrcatW( *ppwszCommandLine, L" -Embedding" ); } } else { ASSERT( SERVERTYPE_SURROGATE == _ServerType || SERVERTYPE_COMPLUS == _ServerType || SERVERTYPE_DLLHOST == _ServerType ); AllocBytes = ( 1 + lstrlenW( DllSurrogate() ) ) * sizeof(WCHAR); *ppwszCommandLine = (WCHAR *) PrivMemAlloc( AllocBytes ); if ( *ppwszCommandLine != NULL ) { lstrcpyW( *ppwszCommandLine, DllSurrogate() ); } } return (*ppwszCommandLine ? S_OK : E_OUTOFMEMORY); } CNamedObject* CClsidData::ServerLaunchMutex() { WCHAR* pwszPath = NULL; WCHAR* pszPathBuf = NULL; if ( SERVERTYPE_SURROGATE == _ServerType ) { pwszPath = DllSurrogate(); // Will never be called any more, ever if ( ! pwszPath || ! *pwszPath ) { ASSERT(_pAppid); pwszPath = _pAppid->AppidString(); //pwszPath = L"dllhost.exe"; } } else if ( DllHostOrComPlusProcess() ) { ASSERT(_pAppid); pwszPath = _pAppid->AppidString(); //pwszPath = L"dllhost.exe"; } else { pwszPath = Server(); // Need to use the base .exe part of the file path here, // there are tests that move the registration of their // server from one dir to another and we need to handle // this while concurrent activations are happening. LPWSTR pszBaseExeName = NULL; // First see how much of a buffer we need DWORD dwRet = GetFullPathName(pwszPath, 0, NULL, NULL); ASSERT(dwRet != 0); pszPathBuf = (WCHAR*)PrivMemAlloc(dwRet * sizeof(WCHAR)); if (!pszPathBuf) return NULL; dwRet = GetFullPathName(pwszPath, dwRet, pszPathBuf, &pszBaseExeName); if ((dwRet == 0) || !pszBaseExeName) { ASSERT(!"Unexpected failure from GetFullPathName"); PrivMemFree(pszPathBuf); return NULL; } // Use the base exe name for the event name pwszPath = pszBaseExeName; } if ( !pwszPath ) { ASSERT(0); PrivMemFree(pszPathBuf); return (NULL); } CNamedObject* pObject = gpNamedObjectTable->GetNamedObject(pwszPath, CNamedObject::MUTEX); PrivMemFree(pszPathBuf); if (pObject) { WaitForSingleObject(pObject->Handle(), INFINITE); } return pObject; } // // CClsidData::ServerRegisterEvent // // Returns a handle to the appropriate register // event for the server in question. // CNamedObject* CClsidData::ServerRegisterEvent() { if ( DllHostOrComPlusProcess() ) { // For dllhost\com+ surrogates, we delegate to the appid ASSERT(_pAppid); return _pAppid->ServerRegisterEvent(); } // Prefix the string with a special string; objects with guid // names are just a touch too common for me to feel comfortable // otherwise. WCHAR wszEventName[GUIDSTR_MAX + sizeof(REGEVENT_PREFIX)]; memcpy(wszEventName, REGEVENT_PREFIX, sizeof(REGEVENT_PREFIX)); memcpy(wszEventName + REGEVENT_PREFIX_STRLEN, _wszClsid, sizeof(_wszClsid)); return gpNamedObjectTable->GetNamedObject(wszEventName, CNamedObject::EVENT); } // // CClsidData::ServerInitializedEvent // // Returns a handle to the appropriate register // event for the server in question. This event is // signaled when initialization is finished. // CNamedObject* CAppidData::ServerInitializedEvent() { // Prefix the string with a special string; objects with guid // names are just a touch too common for me to feel comfortable // otherwise. WCHAR wszEventName[GUIDSTR_MAX + sizeof(INITEVENT_PREFIX)]; memcpy(wszEventName, INITEVENT_PREFIX, sizeof(INITEVENT_PREFIX)); memcpy(wszEventName + INITEVENT_PREFIX_STRLEN, _wszAppid, sizeof(_wszAppid)); return gpNamedObjectTable->GetNamedObject(wszEventName, CNamedObject::EVENT); } // // CClsidData::ServerInitializedEvent // // Returns a handle to the appropriate register // event for the server in question. This event is // signaled when initialization is finished. // // NOTE: The non-DllHost path is currently not used here. // CNamedObject* CClsidData::ServerInitializedEvent() { if ( DllHostOrComPlusProcess() ) { // For dllhost\com+ surrogates, we delegate to the appid ASSERT(_pAppid); return _pAppid->ServerInitializedEvent(); } // Prefix the string with a special string; objects with guid // names are just a touch too common for me to feel comfortable // otherwise. WCHAR wszEventName[GUIDSTR_MAX + sizeof(INITEVENT_PREFIX)]; memcpy(wszEventName, INITEVENT_PREFIX, sizeof(INITEVENT_PREFIX)); memcpy(wszEventName + INITEVENT_PREFIX_STRLEN, _wszClsid, sizeof(_wszClsid)); return gpNamedObjectTable->GetNamedObject(wszEventName, CNamedObject::EVENT); } // // CAppidData::ServerRegisterEvent // // Returns a handle to the appropriate register // event for the server in question. // CNamedObject* CAppidData::ServerRegisterEvent() { // Prefix the string with a special string; objects with guid // names are just a touch too common for me to feel comfortable // otherwise. WCHAR wszEventName[GUIDSTR_MAX + sizeof(REGEVENT_PREFIX)]; memcpy(wszEventName, REGEVENT_PREFIX, sizeof(REGEVENT_PREFIX)); memcpy(wszEventName + REGEVENT_PREFIX_STRLEN, _wszAppid, sizeof(_wszAppid)); return gpNamedObjectTable->GetNamedObject(wszEventName, CNamedObject::EVENT); } //+------------------------------------------------------------------------- // // CClsidData::AddAppPathsToEnv // // Constructs a new environment block with an exe's AppPath value from the // registry appended to the Path environment variable. Simply returns the // given environment block if the clsid's server is not a 32 bit exe or if // no AppPath is found for the exe. // //-------------------------------------------------------------------------- HRESULT CClsidData::AddAppPathsToEnv( IN WCHAR * pEnvBlock, IN DWORD EnvBlockLength, OUT WCHAR ** ppFinalEnvBlock ) { HKEY hAppKey; WCHAR * pwszExe; WCHAR * pwszExeEnd; WCHAR * pwszAppPath; WCHAR * pPath; WCHAR * pNewEnvBlock; WCHAR wszStr[8]; WCHAR wszKeyName[APP_PATH_LEN+MAX_PATH]; DWORD AppPathLength; DWORD EnvFragLength; DWORD Status; BOOL bFoundPath; pwszAppPath = 0; pNewEnvBlock = 0; *ppFinalEnvBlock = pEnvBlock; if ( _ServerType != SERVERTYPE_EXE32 ) return (S_OK); // // Find the exe name by looking for the first .exe sub string which // is followed by a space or null. Only servers registered with a // .exe binary are supported. Otherwise the parsing is ambiguous since // the LocalServer32 can contain paths with spaces as well as optional // arguments. // if ( ! FindExeComponent( _pwszServer, L" ", &pwszExe, &pwszExeEnd ) ) return (S_OK); // // pwszExe points to the beginning of the binary name // pwszExeEnd points to one char past the end of the binary name // memcpy( wszKeyName, APP_PATH, APP_PATH_LEN * sizeof(WCHAR) ); memcpy( &wszKeyName[APP_PATH_LEN], pwszExe, (ULONG) (pwszExeEnd - pwszExe) * sizeof(WCHAR) ); wszKeyName[APP_PATH_LEN + (pwszExeEnd - pwszExe)] = 0; Status = RegOpenKeyEx( HKEY_LOCAL_MACHINE, wszKeyName, 0, KEY_READ, &hAppKey ); if ( ERROR_SUCCESS == Status ) { Status = ReadStringValue( hAppKey, L"Path", &pwszAppPath ); RegCloseKey( hAppKey ); } if ( Status != ERROR_SUCCESS ) return (S_OK); AppPathLength = lstrlenW(pwszAppPath); // New env block size includes space for a new ';' separator in the path. pNewEnvBlock = (WCHAR *) PrivMemAlloc( (EnvBlockLength + 1 + AppPathLength) * sizeof(WCHAR) ); if ( ! pNewEnvBlock ) { PrivMemFree( pwszAppPath ); return (E_OUTOFMEMORY); } pPath = pEnvBlock; bFoundPath = FALSE; for ( ; *pPath; ) { memcpy( wszStr, pPath, 5 * sizeof(WCHAR) ); wszStr[5] = 0; pPath += lstrlenW( pPath ) + 1; if ( lstrcmpiW( wszStr, L"Path=" ) == 0 ) { bFoundPath = TRUE; break; } } if ( bFoundPath ) { pPath--; EnvFragLength = (ULONG) (pPath - pEnvBlock); memcpy( pNewEnvBlock, pEnvBlock, EnvFragLength * sizeof(WCHAR) ); pNewEnvBlock[EnvFragLength] = L';'; memcpy( &pNewEnvBlock[EnvFragLength + 1], pwszAppPath, AppPathLength * sizeof(WCHAR) ); memcpy( &pNewEnvBlock[EnvFragLength + 1 + AppPathLength], pPath, (EnvBlockLength - EnvFragLength) * sizeof(WCHAR) ); *ppFinalEnvBlock = pNewEnvBlock; } else { PrivMemFree( pNewEnvBlock ); } PrivMemFree( pwszAppPath ); return (S_OK); }