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