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