Home | History | Annotate | Download | only in lib
      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 
     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 
     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 
     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 
    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