1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_desktop.hxx" 26 #define UNICODE 27 #define _UNICODE 28 29 #include <cstddef> 30 31 #define WIN32_LEAN_AND_MEAN 32 #if defined _MSC_VER 33 #pragma warning(push, 1) 34 #endif 35 #include <windows.h> 36 #include <shellapi.h> 37 #if defined _MSC_VER 38 #pragma warning(pop) 39 #endif 40 41 #include <tchar.h> 42 43 #include <malloc.h> 44 #include <string.h> 45 #include <stdlib.h> 46 #include <systools/win32/uwinapi.h> 47 48 #include "rtl/string.h" 49 50 #include "../../../source/inc/exithelper.hxx" 51 #include "../extendloaderenvironment.hxx" 52 53 #define PIPE_PREFIX TEXT("\\\\.\\pipe\\OSL_PIPE_") 54 #define PIPE_POSTFIX TEXT("_SingleOfficeIPC_") 55 #define PIPE_TERMINATION_SEQUENCE "InternalIPC::ProcessingDone" 56 57 BOOL WINAPI ConvertSidToStringSid( PSID pSid, LPTSTR* StringSid ) 58 { 59 PSID_IDENTIFIER_AUTHORITY psia; 60 DWORD dwSubAuthorities; 61 DWORD dwSidRev=SID_REVISION; 62 DWORD dwCounter; 63 DWORD dwSidSize; 64 65 // Validate the binary SID. 66 67 if(!IsValidSid(pSid)) return FALSE; 68 69 // Get the identifier authority value from the SID. 70 71 psia = GetSidIdentifierAuthority(pSid); 72 73 // Get the number of subauthorities in the SID. 74 75 dwSubAuthorities = *GetSidSubAuthorityCount(pSid); 76 77 // Compute the buffer length. 78 // S-SID_REVISION- + IdentifierAuthority- + subauthorities- + NULL 79 80 dwSidSize=(15 + 12 + (12 * dwSubAuthorities) + 1) * sizeof(TCHAR); 81 82 *StringSid = (LPTSTR)LocalAlloc( LMEM_FIXED, dwSidSize ); 83 84 // Add 'S' prefix and revision number to the string. 85 86 dwSidSize=wsprintf(*StringSid, TEXT("S-%lu-"), dwSidRev ); 87 88 // Add a SID identifier authority to the string. 89 90 if ( (psia->Value[0] != 0) || (psia->Value[1] != 0) ) 91 { 92 dwSidSize+=wsprintf(*StringSid + lstrlen(*StringSid), 93 TEXT("0x%02hx%02hx%02hx%02hx%02hx%02hx"), 94 (USHORT)psia->Value[0], 95 (USHORT)psia->Value[1], 96 (USHORT)psia->Value[2], 97 (USHORT)psia->Value[3], 98 (USHORT)psia->Value[4], 99 (USHORT)psia->Value[5]); 100 } 101 else 102 { 103 dwSidSize+=wsprintf(*StringSid + lstrlen(*StringSid), 104 TEXT("%lu"), 105 (ULONG)(psia->Value[5] ) + 106 (ULONG)(psia->Value[4] << 8) + 107 (ULONG)(psia->Value[3] << 16) + 108 (ULONG)(psia->Value[2] << 24) ); 109 } 110 111 // Add SID subauthorities to the string. 112 // 113 for (dwCounter=0 ; dwCounter < dwSubAuthorities ; dwCounter++) 114 { 115 dwSidSize+=wsprintf(*StringSid + dwSidSize, TEXT("-%lu"), 116 *GetSidSubAuthority(pSid, dwCounter) ); 117 } 118 119 return TRUE; 120 } 121 122 123 //--------------------------------------------------------------------------- 124 125 static LPTSTR *GetCommandArgs( int *pArgc ) 126 { 127 #ifdef UNICODE 128 return CommandLineToArgvW( GetCommandLineW(), pArgc ); 129 #else 130 *pArgc = __argc; 131 return __argv; 132 #endif 133 } 134 135 //--------------------------------------------------------------------------- 136 137 namespace { 138 139 bool writeArgument(HANDLE pipe, char prefix, WCHAR const * argument) { 140 CHAR szBuffer[4096]; 141 int n = WideCharToMultiByte( 142 CP_UTF8, 0, argument, -1, szBuffer, sizeof (szBuffer), NULL, NULL); 143 char b[1 + 2 * ((sizeof szBuffer) - 1)]; // hopefully does not overflow 144 b[0] = prefix; 145 char * p = b + 1; 146 for (int i = 0; i < n - 1; ++i) { // cannot underflow (n >= 0) 147 char c = szBuffer[i]; 148 switch (c) { 149 case '\0': 150 *p++ = '\\'; 151 *p++ = '0'; 152 break; 153 case ',': 154 *p++ = '\\'; 155 *p++ = ','; 156 break; 157 case '\\': 158 *p++ = '\\'; 159 *p++ = '\\'; 160 break; 161 default: 162 *p++ = c; 163 break; 164 } 165 } 166 DWORD w; 167 return WriteFile(pipe, b, p - b, &w, NULL); 168 } 169 170 } 171 172 #ifdef __MINGW32__ 173 int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE, LPSTR, int ) 174 #else 175 int WINAPI _tWinMain( HINSTANCE, HINSTANCE, LPTSTR, int ) 176 #endif 177 { 178 TCHAR szTargetFileName[MAX_PATH] = TEXT(""); 179 TCHAR szIniDirectory[MAX_PATH]; 180 TCHAR szPerfTuneIniFile[MAX_PATH] = TEXT(""); 181 STARTUPINFO aStartupInfo; 182 183 desktop_win32::extendLoaderEnvironment(szTargetFileName, szIniDirectory); 184 185 ZeroMemory( &aStartupInfo, sizeof(aStartupInfo) ); 186 aStartupInfo.cb = sizeof(aStartupInfo); 187 188 GetStartupInfo( &aStartupInfo ); 189 // Get image path with same name but with .bin extension 190 191 TCHAR szModuleFileName[MAX_PATH]; 192 193 GetModuleFileName( NULL, szModuleFileName, MAX_PATH ); 194 _TCHAR *lpLastSlash = _tcsrchr( szModuleFileName, '\\' ); 195 if ( lpLastSlash ) 196 { 197 size_t len = lpLastSlash - szModuleFileName + 1; 198 _tcsncpy( szPerfTuneIniFile, szModuleFileName, len ); 199 _tcsncpy( szPerfTuneIniFile + len, _T("perftune.ini"), sizeof(szPerfTuneIniFile)/sizeof(szPerfTuneIniFile[0]) - len ); 200 } 201 202 // Create process with same command line, environment and stdio handles which 203 // are directed to the created pipes 204 205 DWORD dwExitCode = (DWORD)-1; 206 207 BOOL fSuccess = FALSE; 208 LPTSTR lpCommandLine = NULL; 209 int argc = 0; 210 LPTSTR * argv = NULL; 211 bool bFirst = true; 212 WCHAR cwd[MAX_PATH]; 213 DWORD cwdLen = GetCurrentDirectoryW(MAX_PATH, cwd); 214 if (cwdLen >= MAX_PATH) { 215 cwdLen = 0; 216 } 217 218 do 219 { 220 TCHAR szKey[32]; 221 222 GetPrivateProfileString( 223 TEXT("PerformanceTuning"), 224 TEXT("FastPipeCommunication"), 225 TEXT("0"), 226 szKey, 227 elementsof(szKey), 228 szPerfTuneIniFile 229 ); 230 231 if ( 0 == _tcscmp( szKey, TEXT("1") ) ) 232 { 233 HANDLE hProcessToken; 234 235 if ( OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &hProcessToken ) ) 236 { 237 TCHAR szPipeName[4096]; 238 239 240 DWORD dwTokenLength = 0; 241 242 243 fSuccess = GetTokenInformation( hProcessToken, TokenUser, NULL, dwTokenLength, &dwTokenLength ); 244 245 PVOID pTokenInfo = _alloca(dwTokenLength); 246 fSuccess = GetTokenInformation( hProcessToken, TokenUser, pTokenInfo, dwTokenLength, &dwTokenLength ); 247 CloseHandle( hProcessToken ); 248 249 PSID pSid = ((PTOKEN_USER)pTokenInfo)->User.Sid; 250 LPTSTR szUserIdent = NULL; 251 TCHAR szSUPD[11] = TEXT("0"); 252 253 fSuccess = ConvertSidToStringSid( pSid, &szUserIdent ); 254 255 _tcsncpy( szPipeName, PIPE_PREFIX, elementsof(szPipeName) ); 256 _tcsncat( szPipeName, szUserIdent, elementsof(szPipeName) - _tcslen(szPipeName) - 1 ); 257 _tcsncat( szPipeName, PIPE_POSTFIX, elementsof(szPipeName) - _tcslen(szPipeName) - 1 ); 258 _tcsncat( szPipeName, _ultot( SUPD, szSUPD, 10), elementsof(szPipeName) - _tcslen(szPipeName) - 1 ); 259 260 LocalFree( szUserIdent ); 261 262 HANDLE hPipe = CreateFile( 263 szPipeName, 264 GENERIC_READ|GENERIC_WRITE, 265 FILE_SHARE_READ | FILE_SHARE_WRITE, 266 NULL, 267 OPEN_EXISTING, 268 FILE_ATTRIBUTE_NORMAL, 269 NULL); 270 271 if ( INVALID_HANDLE_VALUE != hPipe ) 272 { 273 DWORD dwBytesWritten; 274 int argc = 0; 275 LPWSTR *argv = CommandLineToArgvW( GetCommandLine(), &argc ); 276 277 fSuccess = WriteFile( hPipe, RTL_CONSTASCII_STRINGPARAM("InternalIPC::Arguments"), &dwBytesWritten, NULL ); 278 if (fSuccess) { 279 if (cwdLen > 0) { 280 fSuccess = writeArgument(hPipe, '2', cwd); 281 } else { 282 fSuccess = WriteFile( 283 hPipe, RTL_CONSTASCII_STRINGPARAM("0"), 284 &dwBytesWritten, NULL); 285 } 286 } 287 for ( int argn = 1; fSuccess && argn < argc; argn++ ) 288 { 289 fSuccess = writeArgument(hPipe, ',', argv[argn]); 290 } 291 292 if ( fSuccess ) 293 { 294 fSuccess = WriteFile( hPipe, "", 1, &dwBytesWritten, NULL ); 295 if ( fSuccess ) 296 { 297 DWORD dwBytesRead = 0; 298 char *pBuffer = (char *)_alloca( sizeof(PIPE_TERMINATION_SEQUENCE) ); 299 fSuccess = ReadFile( hPipe, pBuffer, sizeof(PIPE_TERMINATION_SEQUENCE) - 1, &dwBytesRead, NULL ); 300 if ( fSuccess ) 301 { 302 pBuffer[dwBytesRead] = 0; 303 if ( 0 != strcmp( PIPE_TERMINATION_SEQUENCE, pBuffer ) ) 304 fSuccess = FALSE; 305 } 306 } 307 } 308 309 CloseHandle( hPipe ); 310 311 return fSuccess ? 0 : -1; 312 } 313 314 } 315 } 316 317 if ( bFirst ) { 318 argv = GetCommandArgs(&argc); 319 std::size_t n = wcslen(argv[0]) + 2; 320 for (int i = 1; i < argc; ++i) { 321 n += wcslen(argv[i]) + 3; 322 } 323 n += MY_LENGTH(L" \"-env:OOO_CWD=2") + 4 * cwdLen + 324 MY_LENGTH(L"\"") + 1; 325 // 4 * cwdLen: each char preceded by backslash, each trailing 326 // backslash doubled 327 lpCommandLine = new WCHAR[n]; 328 } 329 WCHAR * p = desktop_win32::commandLineAppend( 330 lpCommandLine, MY_STRING(L"\"")); 331 p = desktop_win32::commandLineAppend(p, argv[0]); 332 for (int i = 1; i < argc; ++i) { 333 if (bFirst || ::desktop::ExitHelper::E_NORMAL_RESTART == dwExitCode || wcsncmp(argv[i], MY_STRING(L"-env:")) == 0) { 334 p = desktop_win32::commandLineAppend(p, MY_STRING(L"\" \"")); 335 p = desktop_win32::commandLineAppend(p, argv[i]); 336 } 337 } 338 339 p = desktop_win32::commandLineAppend( 340 p, MY_STRING(L"\" \"-env:OOO_CWD=")); 341 if (cwdLen == 0) { 342 p = desktop_win32::commandLineAppend(p, MY_STRING(L"0")); 343 } else { 344 p = desktop_win32::commandLineAppend(p, MY_STRING(L"2")); 345 p = desktop_win32::commandLineAppendEncoded(p, cwd); 346 } 347 desktop_win32::commandLineAppend(p, MY_STRING(L"\"")); 348 bFirst = false; 349 350 TCHAR szParentProcessId[64]; // This is more than large enough for a 128 bit decimal value 351 BOOL bHeadlessMode( FALSE ); 352 353 { 354 // Check command line arguments for "-headless" parameter. We only 355 // set the environment variable "ATTACHED_PARENT_PROCESSID" for the headless 356 // mode as self-destruction of the soffice.bin process can lead to 357 // certain side-effects (log-off can result in data-loss, ".lock" is not deleted. 358 // See 138244 for more information. 359 int argc; 360 LPTSTR *argv = GetCommandArgs( &argc ); 361 362 if ( argc > 1 ) 363 { 364 int n; 365 366 for ( n = 1; n < argc; n++ ) 367 { 368 if ( 0 == _tcsnicmp( argv[n], _T("-headless"), 9 ) ) 369 bHeadlessMode = TRUE; 370 } 371 } 372 } 373 374 if ( _ltot( (long)GetCurrentProcessId(),szParentProcessId, 10 ) && bHeadlessMode ) 375 SetEnvironmentVariable( TEXT("ATTACHED_PARENT_PROCESSID"), szParentProcessId ); 376 377 PROCESS_INFORMATION aProcessInfo; 378 379 fSuccess = CreateProcess( 380 szTargetFileName, 381 lpCommandLine, 382 NULL, 383 NULL, 384 TRUE, 385 0, 386 NULL, 387 szIniDirectory, 388 &aStartupInfo, 389 &aProcessInfo ); 390 391 if ( fSuccess ) 392 { 393 DWORD dwWaitResult; 394 395 do 396 { 397 // On Windows XP it seems as the desktop calls WaitForInputIdle after "OpenWidth" so we have to do so 398 // as if we where processing any messages 399 400 dwWaitResult = MsgWaitForMultipleObjects( 1, &aProcessInfo.hProcess, FALSE, INFINITE, QS_ALLEVENTS ); 401 402 if ( WAIT_OBJECT_0 + 1 == dwWaitResult ) 403 { 404 MSG msg; 405 406 PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ); 407 } 408 } while ( WAIT_OBJECT_0 + 1 == dwWaitResult ); 409 410 dwExitCode = 0; 411 GetExitCodeProcess( aProcessInfo.hProcess, &dwExitCode ); 412 413 CloseHandle( aProcessInfo.hProcess ); 414 CloseHandle( aProcessInfo.hThread ); 415 } 416 } while ( fSuccess 417 && ( ::desktop::ExitHelper::E_CRASH_WITH_RESTART == dwExitCode || ::desktop::ExitHelper::E_NORMAL_RESTART == dwExitCode )); 418 delete[] lpCommandLine; 419 420 return fSuccess ? dwExitCode : -1; 421 } 422