• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include <windows.h>
6 #include <Sddl.h>  // For ConvertSidToStringSidW.
7 #include <string>
8 
9 #include "base/memory/scoped_ptr.h"
10 #include "base/strings/string16.h"
11 #include "rlz/lib/assert.h"
12 
13 namespace rlz_lib {
14 
15 namespace {
16 
GetSystemVolumeSerialNumber(int * number)17 bool GetSystemVolumeSerialNumber(int* number) {
18   if (!number)
19     return false;
20 
21   *number = 0;
22 
23   // Find the system root path (e.g: C:\).
24   wchar_t system_path[MAX_PATH + 1];
25   if (!GetSystemDirectoryW(system_path, MAX_PATH))
26     return false;
27 
28   wchar_t* first_slash = wcspbrk(system_path, L"\\/");
29   if (first_slash != NULL)
30     *(first_slash + 1) = 0;
31 
32   DWORD number_local = 0;
33   if (!GetVolumeInformationW(system_path, NULL, 0, &number_local, NULL, NULL,
34                              NULL, 0))
35     return false;
36 
37   *number = number_local;
38   return true;
39 }
40 
GetComputerSid(const wchar_t * account_name,SID * sid,DWORD sid_size)41 bool GetComputerSid(const wchar_t* account_name, SID* sid, DWORD sid_size) {
42   static const DWORD kStartDomainLength = 128;  // reasonable to start with
43 
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;
48 
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
55     // here.
56     if (sid_dword_size > sid_size)
57       return false;
58 
59     if (domain_size > kStartDomainLength)
60       domain_buffer.reset(new wchar_t[domain_size]);
61 
62     success = ::LookupAccountNameW(NULL, account_name, sid, &sid_dword_size,
63                                    domain_buffer.get(), &domain_size,
64                                    &sid_name_use);
65   }
66 
67   return success != FALSE;
68 }
69 
ConvertSidToString(SID * sid)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);
77   }
78 #else
79   SID_IDENTIFIER_AUTHORITY* sia = ::GetSidIdentifierAuthority(sid);
80 
81   if(sia->Value[0] || sia->Value[1]) {
82     base::SStringPrintf(
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]);
87   } else {
88     ULONG authority = 0;
89     for (int i = 2; i < 6; ++i) {
90       authority <<= 8;
91       authority |= sia->Value[i];
92     }
93     base::SStringPrintf(&sid_string, L"S-%d-%lu", SID_REVISION, authority);
94   }
95 
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));
99 #endif
100 
101   return sid_string;
102 }
103 
104 }  // namespace
105 
GetRawMachineId(base::string16 * sid_string,int * volume_id)106 bool GetRawMachineId(base::string16* sid_string, int* volume_id) {
107   // Calculate the Windows SID.
108 
109   wchar_t computer_name[MAX_COMPUTERNAME_LENGTH + 1] = {0};
110   DWORD size = arraysize(computer_name);
111 
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);
117     }
118   }
119 
120   // Get the system drive volume serial number.
121   *volume_id = 0;
122   if (!GetSystemVolumeSerialNumber(volume_id)) {
123     ASSERT_STRING("GetMachineId: Failed to retrieve volume serial number");
124     *volume_id = 0;
125   }
126 
127   return true;
128 }
129 
130 }  // namespace rlz_lib
131