forked from mirrors/gecko-dev
		
	Also adds missing includes in some files, these were previously only transivitely included through mozilla/TypeTraits.h. Differential Revision: https://phabricator.services.mozilla.com/D68561 --HG-- extra : moz-landing-system : lando
		
			
				
	
	
		
			178 lines
		
	
	
	
		
			6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			178 lines
		
	
	
	
		
			6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | 
						|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
 | 
						|
/* This Source Code Form is subject to the terms of the Mozilla Public
 | 
						|
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 | 
						|
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
 | 
						|
 | 
						|
#ifndef mozilla_ShellHeaderOnlyUtils_h
 | 
						|
#define mozilla_ShellHeaderOnlyUtils_h
 | 
						|
 | 
						|
#include "mozilla/WinHeaderOnlyUtils.h"
 | 
						|
 | 
						|
#include <objbase.h>
 | 
						|
 | 
						|
#include <exdisp.h>
 | 
						|
#include <shldisp.h>
 | 
						|
#include <shlobj.h>
 | 
						|
#include <shlwapi.h>
 | 
						|
#include <shobjidl.h>
 | 
						|
#include <shtypes.h>
 | 
						|
// NB: include this after shldisp.h so its macros do not conflict with COM
 | 
						|
// interfaces defined by shldisp.h
 | 
						|
#include <shellapi.h>
 | 
						|
#include <type_traits>
 | 
						|
 | 
						|
#include <comdef.h>
 | 
						|
#include <comutil.h>
 | 
						|
 | 
						|
#include "mozilla/RefPtr.h"
 | 
						|
#include "mozilla/UniquePtr.h"
 | 
						|
 | 
						|
namespace mozilla {
 | 
						|
 | 
						|
/**
 | 
						|
 * Ask the current user's Desktop to ShellExecute on our behalf, thus causing
 | 
						|
 * the resulting launched process to inherit its security priviliges from
 | 
						|
 * Explorer instead of our process.
 | 
						|
 *
 | 
						|
 * This is useful in two scenarios, in particular:
 | 
						|
 *   * We are running as an elevated user and we want to start something as the
 | 
						|
 *     "normal" user;
 | 
						|
 *   * We are starting a process that is incompatible with our process's
 | 
						|
 *     process mitigation policies. By delegating to Explorer, the child process
 | 
						|
 *     will not be affected by our process mitigations.
 | 
						|
 *
 | 
						|
 * Since this communication happens over DCOM, Explorer's COM DACL governs
 | 
						|
 * whether or not we can execute against it, thus avoiding privilege escalation.
 | 
						|
 */
 | 
						|
inline LauncherVoidResult ShellExecuteByExplorer(const _bstr_t& aPath,
 | 
						|
                                                 const _variant_t& aArgs,
 | 
						|
                                                 const _variant_t& aVerb,
 | 
						|
                                                 const _variant_t& aWorkingDir,
 | 
						|
                                                 const _variant_t& aShowCmd) {
 | 
						|
  // NB: Explorer may be a local server, not an inproc server
 | 
						|
  RefPtr<IShellWindows> shellWindows;
 | 
						|
  HRESULT hr = ::CoCreateInstance(
 | 
						|
      CLSID_ShellWindows, nullptr, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
 | 
						|
      IID_IShellWindows, getter_AddRefs(shellWindows));
 | 
						|
  if (FAILED(hr)) {
 | 
						|
    return LAUNCHER_ERROR_FROM_HRESULT(hr);
 | 
						|
  }
 | 
						|
 | 
						|
  // 1. Find the shell view for the desktop.
 | 
						|
  _variant_t loc(int(CSIDL_DESKTOP));
 | 
						|
  _variant_t empty;
 | 
						|
  long hwnd;
 | 
						|
  RefPtr<IDispatch> dispDesktop;
 | 
						|
  hr = shellWindows->FindWindowSW(&loc, &empty, SWC_DESKTOP, &hwnd,
 | 
						|
                                  SWFO_NEEDDISPATCH,
 | 
						|
                                  getter_AddRefs(dispDesktop));
 | 
						|
  if (FAILED(hr)) {
 | 
						|
    return LAUNCHER_ERROR_FROM_HRESULT(hr);
 | 
						|
  }
 | 
						|
 | 
						|
  if (hr == S_FALSE) {
 | 
						|
    // The call succeeded but the window was not found.
 | 
						|
    return LAUNCHER_ERROR_FROM_WIN32(ERROR_NOT_FOUND);
 | 
						|
  }
 | 
						|
 | 
						|
  RefPtr<IServiceProvider> servProv;
 | 
						|
  hr = dispDesktop->QueryInterface(IID_IServiceProvider,
 | 
						|
                                   getter_AddRefs(servProv));
 | 
						|
  if (FAILED(hr)) {
 | 
						|
    return LAUNCHER_ERROR_FROM_HRESULT(hr);
 | 
						|
  }
 | 
						|
 | 
						|
  RefPtr<IShellBrowser> browser;
 | 
						|
  hr = servProv->QueryService(SID_STopLevelBrowser, IID_IShellBrowser,
 | 
						|
                              getter_AddRefs(browser));
 | 
						|
  if (FAILED(hr)) {
 | 
						|
    return LAUNCHER_ERROR_FROM_HRESULT(hr);
 | 
						|
  }
 | 
						|
 | 
						|
  RefPtr<IShellView> activeShellView;
 | 
						|
  hr = browser->QueryActiveShellView(getter_AddRefs(activeShellView));
 | 
						|
  if (FAILED(hr)) {
 | 
						|
    return LAUNCHER_ERROR_FROM_HRESULT(hr);
 | 
						|
  }
 | 
						|
 | 
						|
  // 2. Get the automation object for the desktop.
 | 
						|
  RefPtr<IDispatch> dispView;
 | 
						|
  hr = activeShellView->GetItemObject(SVGIO_BACKGROUND, IID_IDispatch,
 | 
						|
                                      getter_AddRefs(dispView));
 | 
						|
  if (FAILED(hr)) {
 | 
						|
    return LAUNCHER_ERROR_FROM_HRESULT(hr);
 | 
						|
  }
 | 
						|
 | 
						|
  RefPtr<IShellFolderViewDual> folderView;
 | 
						|
  hr = dispView->QueryInterface(IID_IShellFolderViewDual,
 | 
						|
                                getter_AddRefs(folderView));
 | 
						|
  if (FAILED(hr)) {
 | 
						|
    return LAUNCHER_ERROR_FROM_HRESULT(hr);
 | 
						|
  }
 | 
						|
 | 
						|
  // 3. Get the interface to IShellDispatch2
 | 
						|
  RefPtr<IDispatch> dispShell;
 | 
						|
  hr = folderView->get_Application(getter_AddRefs(dispShell));
 | 
						|
  if (FAILED(hr)) {
 | 
						|
    return LAUNCHER_ERROR_FROM_HRESULT(hr);
 | 
						|
  }
 | 
						|
 | 
						|
  RefPtr<IShellDispatch2> shellDisp;
 | 
						|
  hr =
 | 
						|
      dispShell->QueryInterface(IID_IShellDispatch2, getter_AddRefs(shellDisp));
 | 
						|
  if (FAILED(hr)) {
 | 
						|
    return LAUNCHER_ERROR_FROM_HRESULT(hr);
 | 
						|
  }
 | 
						|
 | 
						|
  // Passing the foreground privilege so that the shell can launch an
 | 
						|
  // application in the foreground.  This fails with E_ACCESSDENIED if the
 | 
						|
  // current window is shown in the background.  We keep a soft assert for
 | 
						|
  // the other failures to investigate how it happened.
 | 
						|
  hr = ::CoAllowSetForegroundWindow(shellDisp, nullptr);
 | 
						|
  MOZ_ASSERT(SUCCEEDED(hr) || hr == E_ACCESSDENIED);
 | 
						|
 | 
						|
  // shellapi.h macros interfere with the correct naming of the method being
 | 
						|
  // called on IShellDispatch2. Temporarily remove that definition.
 | 
						|
#if defined(ShellExecute)
 | 
						|
#  define MOZ_REDEFINE_SHELLEXECUTE
 | 
						|
#  undef ShellExecute
 | 
						|
#endif  // defined(ShellExecute)
 | 
						|
 | 
						|
  // 4. Now call IShellDispatch2::ShellExecute to ask Explorer to execute.
 | 
						|
  hr = shellDisp->ShellExecute(aPath, aArgs, aWorkingDir, aVerb, aShowCmd);
 | 
						|
  if (FAILED(hr)) {
 | 
						|
    return LAUNCHER_ERROR_FROM_HRESULT(hr);
 | 
						|
  }
 | 
						|
 | 
						|
  // Restore the macro that was removed prior to IShellDispatch2::ShellExecute
 | 
						|
#if defined(MOZ_REDEFINE_SHELLEXECUTE)
 | 
						|
#  if defined(UNICODE)
 | 
						|
#    define ShellExecute ShellExecuteW
 | 
						|
#  else
 | 
						|
#    define ShellExecute ShellExecuteA
 | 
						|
#  endif
 | 
						|
#  undef MOZ_REDEFINE_SHELLEXECUTE
 | 
						|
#endif  // defined(MOZ_REDEFINE_SHELLEXECUTE)
 | 
						|
 | 
						|
  return Ok();
 | 
						|
}
 | 
						|
 | 
						|
using UniqueAbsolutePidl =
 | 
						|
    UniquePtr<std::remove_pointer_t<PIDLIST_ABSOLUTE>, CoTaskMemFreeDeleter>;
 | 
						|
 | 
						|
inline LauncherResult<UniqueAbsolutePidl> ShellParseDisplayName(
 | 
						|
    const wchar_t* aPath) {
 | 
						|
  PIDLIST_ABSOLUTE rawAbsPidl = nullptr;
 | 
						|
  SFGAOF sfgao;
 | 
						|
  HRESULT hr = ::SHParseDisplayName(aPath, nullptr, &rawAbsPidl, 0, &sfgao);
 | 
						|
  if (FAILED(hr)) {
 | 
						|
    return LAUNCHER_ERROR_FROM_HRESULT(hr);
 | 
						|
  }
 | 
						|
 | 
						|
  return UniqueAbsolutePidl(rawAbsPidl);
 | 
						|
}
 | 
						|
 | 
						|
}  // namespace mozilla
 | 
						|
 | 
						|
#endif  // mozilla_ShellHeaderOnlyUtils_h
 |