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 
ConvertSidToStringSid(PSID pSid,LPTSTR * StringSid)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 
GetCommandArgs(int * pArgc)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 
writeArgument(HANDLE pipe,char prefix,WCHAR const * argument)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__
WinMain(HINSTANCE hInstance,HINSTANCE,LPSTR,int)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