get_desktop_directory_win.cc 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
  1. // Copyright 2019 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "remoting/host/file_transfer/get_desktop_directory.h"
  5. #include <windows.h>
  6. #include <shlobj.h>
  7. #include "base/logging.h"
  8. #include "base/win/scoped_handle.h"
  9. namespace remoting {
  10. // We can't use PathService on Windows because it doesn't play nicely with
  11. // impersonation. Even if we disable PathService's own cache, the Windows API
  12. // itself does process-wide caching that can cause trouble on an impersonating
  13. // thread. As such, we have to call the relevant API directly and be explicit
  14. // about wanting impersonation handling.
  15. protocol::FileTransferResult<base::FilePath> GetDesktopDirectory() {
  16. // SHGetFolderPath on Windows 7 doesn't seem to like the pseudo handle
  17. // returned by GetCurrentThreadToken(), so call OpenThreadToken to get a real
  18. // handle.
  19. HANDLE user_token = nullptr;
  20. if (!OpenThreadToken(GetCurrentThread(),
  21. TOKEN_QUERY | TOKEN_IMPERSONATE | TOKEN_DUPLICATE, TRUE,
  22. &user_token)) {
  23. PLOG(ERROR) << "Failed to open thread token";
  24. return protocol::MakeFileTransferError(
  25. FROM_HERE, protocol::FileTransfer_Error_Type_UNEXPECTED_ERROR,
  26. GetLastError());
  27. }
  28. base::win::ScopedHandle scoped_user_token(user_token);
  29. wchar_t buffer[MAX_PATH];
  30. buffer[0] = 0;
  31. // While passing NULL for the third parameter would normally get the directory
  32. // for the current user, there are process-wide caches that can cause trouble
  33. // when impersonation is in play, so specify the token explicitly.
  34. HRESULT hr =
  35. SHGetFolderPath(NULL, CSIDL_DESKTOPDIRECTORY, scoped_user_token.Get(),
  36. SHGFP_TYPE_CURRENT, buffer);
  37. if (FAILED(hr)) {
  38. LOG(ERROR) << "Failed to get desktop directory: " << hr;
  39. return protocol::MakeFileTransferError(
  40. FROM_HERE, protocol::FileTransfer_Error_Type_UNEXPECTED_ERROR, hr);
  41. }
  42. return {kSuccessTag, buffer};
  43. }
  44. } // namespace remoting