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