1 // Copyright (c) 2012 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.
6 #include <Sddl.h> // For ConvertSidToStringSidW.
9 #include "base/memory/scoped_ptr.h"
10 #include "base/strings/string16.h"
11 #include "rlz/lib/assert.h"
17 bool GetSystemVolumeSerialNumber(int* number
) {
23 // Find the system root path (e.g: C:\).
24 wchar_t system_path
[MAX_PATH
+ 1];
25 if (!GetSystemDirectoryW(system_path
, MAX_PATH
))
28 wchar_t* first_slash
= wcspbrk(system_path
, L
"\\/");
29 if (first_slash
!= NULL
)
30 *(first_slash
+ 1) = 0;
32 DWORD number_local
= 0;
33 if (!GetVolumeInformationW(system_path
, NULL
, 0, &number_local
, NULL
, NULL
,
37 *number
= number_local
;
41 bool GetComputerSid(const wchar_t* account_name
, SID
* sid
, DWORD sid_size
) {
42 static const DWORD kStartDomainLength
= 128; // reasonable to start with
44 scoped_ptr
<wchar_t[]> domain_buffer(new wchar_t[kStartDomainLength
]);
45 DWORD domain_size
= kStartDomainLength
;
46 DWORD sid_dword_size
= sid_size
;
47 SID_NAME_USE sid_name_use
;
49 BOOL success
= ::LookupAccountNameW(NULL
, account_name
, sid
,
50 &sid_dword_size
, domain_buffer
.get(),
51 &domain_size
, &sid_name_use
);
52 if (!success
&& ::GetLastError() == ERROR_INSUFFICIENT_BUFFER
) {
53 // We could have gotten the insufficient buffer error because
54 // one or both of sid and szDomain was too small. Check for that
56 if (sid_dword_size
> sid_size
)
59 if (domain_size
> kStartDomainLength
)
60 domain_buffer
.reset(new wchar_t[domain_size
]);
62 success
= ::LookupAccountNameW(NULL
, account_name
, sid
, &sid_dword_size
,
63 domain_buffer
.get(), &domain_size
,
67 return success
!= FALSE
;
70 std::wstring
ConvertSidToString(SID
* sid
) {
71 std::wstring sid_string
;
72 #if _WIN32_WINNT >= 0x500
73 wchar_t* sid_buffer
= NULL
;
74 if (ConvertSidToStringSidW(sid
, &sid_buffer
)) {
75 sid_string
= sid_buffer
;
76 LocalFree(sid_buffer
);
79 SID_IDENTIFIER_AUTHORITY
* sia
= ::GetSidIdentifierAuthority(sid
);
81 if(sia
->Value
[0] || sia
->Value
[1]) {
83 &sid_string
, L
"S-%d-0x%02hx%02hx%02hx%02hx%02hx%02hx",
84 SID_REVISION
, (USHORT
)sia
->Value
[0], (USHORT
)sia
->Value
[1],
85 (USHORT
)sia
->Value
[2], (USHORT
)sia
->Value
[3], (USHORT
)sia
->Value
[4],
86 (USHORT
)sia
->Value
[5]);
89 for (int i
= 2; i
< 6; ++i
) {
91 authority
|= sia
->Value
[i
];
93 base::SStringPrintf(&sid_string
, L
"S-%d-%lu", SID_REVISION
, authority
);
96 int sub_auth_count
= *::GetSidSubAuthorityCount(sid
);
97 for(int i
= 0; i
< sub_auth_count
; ++i
)
98 base::StringAppendF(&sid_string
, L
"-%lu", *::GetSidSubAuthority(sid
, i
));
106 bool GetRawMachineId(base::string16
* sid_string
, int* volume_id
) {
107 // Calculate the Windows SID.
109 wchar_t computer_name
[MAX_COMPUTERNAME_LENGTH
+ 1] = {0};
110 DWORD size
= arraysize(computer_name
);
112 if (GetComputerNameW(computer_name
, &size
)) {
113 char sid_buffer
[SECURITY_MAX_SID_SIZE
];
114 SID
* sid
= reinterpret_cast<SID
*>(sid_buffer
);
115 if (GetComputerSid(computer_name
, sid
, SECURITY_MAX_SID_SIZE
)) {
116 *sid_string
= ConvertSidToString(sid
);
120 // Get the system drive volume serial number.
122 if (!GetSystemVolumeSerialNumber(volume_id
)) {
123 ASSERT_STRING("GetMachineId: Failed to retrieve volume serial number");
130 } // namespace rlz_lib