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