xref: /AOO41X/main/desktop/win32/source/officeloader/officeloader.cxx (revision 2722ceddc26af33ca9ed6a22fc3c4dfb805171c3)
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