device_id_win.cc 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. // Copyright 2015 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 "services/preferences/tracked/device_id.h"
  5. #include <windows.h>
  6. #include <sddl.h> // For ConvertSidToStringSidA.
  7. #include <memory>
  8. #include "base/check.h"
  9. MachineIdStatus GetDeterministicMachineSpecificId(std::string* machine_id) {
  10. DCHECK(machine_id);
  11. wchar_t computer_name[MAX_COMPUTERNAME_LENGTH + 1] = {};
  12. DWORD computer_name_size = std::size(computer_name);
  13. if (!::GetComputerNameW(computer_name, &computer_name_size))
  14. return MachineIdStatus::FAILURE;
  15. DWORD sid_size = SECURITY_MAX_SID_SIZE;
  16. char sid_buffer[SECURITY_MAX_SID_SIZE];
  17. SID* sid = reinterpret_cast<SID*>(sid_buffer);
  18. DWORD domain_size = 128; // Will expand below if needed.
  19. std::unique_ptr<wchar_t[]> domain_buffer(new wchar_t[domain_size]);
  20. SID_NAME_USE sid_name_use;
  21. // Although the fifth argument to |LookupAccountNameW()|,
  22. // |ReferencedDomainName|, is annotated as |_Out_opt_|, if a null
  23. // value is passed in, zero is returned and |GetLastError()| will
  24. // return |ERROR_INSUFFICIENT_BUFFER| (assuming that nothing else went
  25. // wrong). In order to ensure that the call to |LookupAccountNameW()|
  26. // has succeeded, it is necessary to include the following logic and
  27. // obtain the domain name.
  28. if (!::LookupAccountNameW(nullptr, computer_name, sid, &sid_size,
  29. domain_buffer.get(), &domain_size, &sid_name_use)) {
  30. // If the initial size of |domain_buffer| was too small, the
  31. // required size is now found in |domain_size|. Resize and try
  32. // again.
  33. if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER)
  34. return MachineIdStatus::FAILURE;
  35. domain_buffer.reset(new wchar_t[domain_size]);
  36. if (!::LookupAccountNameW(nullptr, computer_name, sid, &sid_size,
  37. domain_buffer.get(), &domain_size,
  38. &sid_name_use)) {
  39. return MachineIdStatus::FAILURE;
  40. }
  41. }
  42. // Ensure that the correct type of SID was obtained. The
  43. // |LookupAccountNameW()| function seems to always return
  44. // |SidTypeDomain| instead of |SidTypeComputer| when the computer name
  45. // is passed in as its second argument and therefore both enum values
  46. // will be considered acceptable. If the computer name and user name
  47. // coincide, |LookupAccountNameW()| seems to always return the machine
  48. // SID and set the returned enum to |SidTypeDomain|.
  49. DCHECK(sid_name_use == SID_NAME_USE::SidTypeComputer ||
  50. sid_name_use == SID_NAME_USE::SidTypeDomain);
  51. char* sid_string = nullptr;
  52. if (!::ConvertSidToStringSidA(sid, &sid_string))
  53. return MachineIdStatus::FAILURE;
  54. *machine_id = sid_string;
  55. ::LocalFree(sid_string);
  56. return MachineIdStatus::SUCCESS;
  57. }