|
18 | 18 | */ |
19 | 19 |
|
20 | 20 | #include <algorithm> |
| 21 | +#include <cassert> |
21 | 22 |
|
22 | 23 | #include <osl/diagnose.h> |
| 24 | +#include <osl/process.h> |
23 | 25 | #include <sal/log.hxx> |
24 | 26 | #include "SysShExec.hxx" |
25 | 27 | #include <osl/file.hxx> |
|
30 | 32 | #include <com/sun/star/uri/UriReferenceFactory.hpp> |
31 | 33 | #include <cppuhelper/supportsservice.hxx> |
32 | 34 | #include <o3tl/char16_t2wchar_t.hxx> |
| 35 | +#include <o3tl/runtimetooustring.hxx> |
33 | 36 |
|
34 | 37 | #define WIN32_LEAN_AND_MEAN |
35 | 38 | #include <windows.h> |
36 | 39 | #include <shellapi.h> |
| 40 | +#include <Shobjidl.h> |
37 | 41 | #include <objbase.h> |
38 | 42 |
|
| 43 | +#include <systools/win32/comtools.hxx> |
| 44 | + |
39 | 45 | using com::sun::star::uno::Reference; |
40 | 46 | using com::sun::star::uno::RuntimeException; |
41 | 47 | using com::sun::star::uno::Sequence; |
@@ -242,6 +248,18 @@ CSysShExec::CSysShExec( const Reference< css::uno::XComponentContext >& xContext |
242 | 248 |
|
243 | 249 | namespace |
244 | 250 | { |
| 251 | +bool checkExtension(OUString const & extension, OUString const & blacklist) { |
| 252 | + assert(!extension.isEmpty()); |
| 253 | + for (sal_Int32 i = 0; i != -1;) { |
| 254 | + OUString tok = blacklist.getToken(0, ';', i); |
| 255 | + tok.startsWith(".", &tok); |
| 256 | + if (extension.equalsIgnoreAsciiCase(tok)) { |
| 257 | + return false; |
| 258 | + } |
| 259 | + } |
| 260 | + return true; |
| 261 | +} |
| 262 | + |
245 | 263 | // This callback checks if the found window is the specified process's top-level window, |
246 | 264 | // and activates the first found such window. |
247 | 265 | BOOL CALLBACK FindAndActivateProcWnd(HWND hwnd, LPARAM lParam) |
@@ -295,6 +313,102 @@ void SAL_CALL CSysShExec::execute( const OUString& aCommand, const OUString& aPa |
295 | 313 | + aCommand, |
296 | 314 | static_cast< cppu::OWeakObject * >(this), 0); |
297 | 315 | } |
| 316 | + if (uri->getScheme().equalsIgnoreAsciiCase("file")) { |
| 317 | + OUString pathname; |
| 318 | + auto const e1 = osl::FileBase::getSystemPathFromFileURL(aCommand, pathname); |
| 319 | + if (e1 != osl::FileBase::E_None) { |
| 320 | + throw css::lang::IllegalArgumentException( |
| 321 | + ("XSystemShellExecute.execute, getSystemPathFromFileURL <" + aCommand |
| 322 | + + "> failed with " + OUString::number(e1)), |
| 323 | + {}, 0); |
| 324 | + } |
| 325 | + for (int i = 0;; ++i) { |
| 326 | + SHFILEINFOW info; |
| 327 | + if (SHGetFileInfoW( |
| 328 | + o3tl::toW(pathname.getStr()), 0, &info, sizeof info, SHGFI_EXETYPE) |
| 329 | + != 0) |
| 330 | + { |
| 331 | + throw css::lang::IllegalArgumentException( |
| 332 | + "XSystemShellExecute.execute, cannot process <" + aCommand + ">", {}, 0); |
| 333 | + } |
| 334 | + if (SHGetFileInfoW( |
| 335 | + o3tl::toW(pathname.getStr()), 0, &info, sizeof info, SHGFI_ATTRIBUTES) |
| 336 | + == 0) |
| 337 | + { |
| 338 | + throw css::lang::IllegalArgumentException( |
| 339 | + "XSystemShellExecute.execute, SHGetFileInfoW(" + pathname + ") failed", {}, |
| 340 | + 0); |
| 341 | + } |
| 342 | + if ((info.dwAttributes & SFGAO_LINK) == 0) { |
| 343 | + break; |
| 344 | + } |
| 345 | + sal::systools::COMReference<IShellLinkW> link; |
| 346 | + auto e2 = CoCreateInstance( |
| 347 | + CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_IShellLinkW, |
| 348 | + reinterpret_cast<LPVOID *>(&link)); |
| 349 | + if (FAILED(e2)) { |
| 350 | + throw css::lang::IllegalArgumentException( |
| 351 | + ("XSystemShellExecute.execute, CoCreateInstance failed with " |
| 352 | + + OUString::number(e2)), |
| 353 | + {}, 0); |
| 354 | + } |
| 355 | + sal::systools::COMReference<IPersistFile> file; |
| 356 | + try { |
| 357 | + file = link.QueryInterface<IPersistFile>(IID_IPersistFile); |
| 358 | + } catch(sal::systools::ComError & e3) { |
| 359 | + throw css::lang::IllegalArgumentException( |
| 360 | + ("XSystemShellExecute.execute, QueryInterface failed with: " |
| 361 | + + o3tl::runtimeToOUString(e3.what())), |
| 362 | + {}, 0); |
| 363 | + } |
| 364 | + e2 = file->Load(o3tl::toW(pathname.getStr()), STGM_READ); |
| 365 | + if (FAILED(e2)) { |
| 366 | + throw css::lang::IllegalArgumentException( |
| 367 | + ("XSystemShellExecute.execute, IPersistFile.Load failed with " |
| 368 | + + OUString::number(e2)), |
| 369 | + {}, 0); |
| 370 | + } |
| 371 | + e2 = link->Resolve(nullptr, SLR_UPDATE | SLR_NO_UI); |
| 372 | + if (FAILED(e2)) { |
| 373 | + throw css::lang::IllegalArgumentException( |
| 374 | + ("XSystemShellExecute.execute, IShellLink.Resolve failed with " |
| 375 | + + OUString::number(e2)), |
| 376 | + {}, 0); |
| 377 | + } |
| 378 | + wchar_t path[MAX_PATH]; |
| 379 | + WIN32_FIND_DATAW wfd; |
| 380 | + e2 = link->GetPath(path, MAX_PATH, &wfd, SLGP_RAWPATH); |
| 381 | + if (FAILED(e2)) { |
| 382 | + throw css::lang::IllegalArgumentException( |
| 383 | + ("XSystemShellExecute.execute, IShellLink.GetPath failed with " |
| 384 | + + OUString::number(e2)), |
| 385 | + {}, 0); |
| 386 | + } |
| 387 | + pathname = o3tl::toU(path); |
| 388 | + // Fail at some arbitrary nesting depth, to avoid an infinite loop: |
| 389 | + if (i == 30) { |
| 390 | + throw css::lang::IllegalArgumentException( |
| 391 | + "XSystemShellExecute.execute, link depth exceeded for <" + aCommand + ">", |
| 392 | + {}, 0); |
| 393 | + } |
| 394 | + } |
| 395 | + auto const n = pathname.lastIndexOf('.'); |
| 396 | + if (n > pathname.lastIndexOf('\\')) { |
| 397 | + auto const ext = pathname.copy(n + 1); |
| 398 | + OUString env; |
| 399 | + if (osl_getEnvironment(OUString("PATHEXT").pData, &env.pData) != osl_Process_E_None) |
| 400 | + { |
| 401 | + SAL_INFO("shell", "osl_getEnvironment(PATHEXT) failed"); |
| 402 | + } |
| 403 | + if (!(checkExtension(ext, env) |
| 404 | + && checkExtension( |
| 405 | + ext, ".COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC;.PY"))) |
| 406 | + { |
| 407 | + throw css::lang::IllegalArgumentException( |
| 408 | + "XSystemShellExecute.execute, cannot process <" + aCommand + ">", {}, 0); |
| 409 | + } |
| 410 | + } |
| 411 | + } |
298 | 412 | } |
299 | 413 |
|
300 | 414 | /* #i4789#; jump mark detection on system paths |
|
0 commit comments