summaryrefslogtreecommitdiffstats
path: root/dom/media/gmp/rlz/win/lib/machine_id_win.cc
blob: 85f1d6cf54a89ec7d70307aa7e61bf52b320fb9d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <windows.h>
#include <sddl.h>  // For ConvertSidToStringSidW.

#include <memory>
#include <string>
#include <vector>

#include "mozilla/ArrayUtils.h"

#include "rlz/lib/assert.h"

namespace rlz_lib {

namespace {

bool GetSystemVolumeSerialNumber(int* number) {
  if (!number)
    return false;

  *number = 0;

  // Find the system root path (e.g: C:\).
  wchar_t system_path[MAX_PATH + 1];
  if (!GetSystemDirectoryW(system_path, MAX_PATH))
    return false;

  wchar_t* first_slash = wcspbrk(system_path, L"\\/");
  if (first_slash != NULL)
    *(first_slash + 1) = 0;

  DWORD number_local = 0;
  if (!GetVolumeInformationW(system_path, NULL, 0, &number_local, NULL, NULL,
                             NULL, 0))
    return false;

  *number = (int)number_local;
  return true;
}

bool GetComputerSid(const wchar_t* account_name, SID* sid, DWORD sid_size) {
  static const DWORD kStartDomainLength = 128;  // reasonable to start with

  std::unique_ptr<wchar_t[]> domain_buffer(new wchar_t[kStartDomainLength]);
  DWORD domain_size = kStartDomainLength;
  DWORD sid_dword_size = sid_size;
  SID_NAME_USE sid_name_use;

  BOOL success = ::LookupAccountNameW(NULL, account_name, sid,
                                      &sid_dword_size, domain_buffer.get(),
                                      &domain_size, &sid_name_use);
  if (!success && ::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
    // We could have gotten the insufficient buffer error because
    // one or both of sid and szDomain was too small. Check for that
    // here.
    if (sid_dword_size > sid_size)
      return false;

    if (domain_size > kStartDomainLength)
      domain_buffer.reset(new wchar_t[domain_size]);

    success = ::LookupAccountNameW(NULL, account_name, sid, &sid_dword_size,
                                   domain_buffer.get(), &domain_size,
                                   &sid_name_use);
  }

  return success != FALSE;
}

std::vector<uint8_t> ConvertSidToBytes(SID* sid) {
  std::wstring sid_string;
#if _WIN32_WINNT >= 0x500
  wchar_t* sid_buffer = NULL;
  if (ConvertSidToStringSidW(sid, &sid_buffer)) {
    sid_string = sid_buffer;
    LocalFree(sid_buffer);
  }
#else
  SID_IDENTIFIER_AUTHORITY* sia = ::GetSidIdentifierAuthority(sid);

  if(sia->Value[0] || sia->Value[1]) {
    base::SStringPrintf(
        &sid_string, L"S-%d-0x%02hx%02hx%02hx%02hx%02hx%02hx",
        SID_REVISION, (USHORT)sia->Value[0], (USHORT)sia->Value[1],
        (USHORT)sia->Value[2], (USHORT)sia->Value[3], (USHORT)sia->Value[4],
        (USHORT)sia->Value[5]);
  } else {
    ULONG authority = 0;
    for (int i = 2; i < 6; ++i) {
      authority <<= 8;
      authority |= sia->Value[i];
    }
    base::SStringPrintf(&sid_string, L"S-%d-%lu", SID_REVISION, authority);
  }

  int sub_auth_count = *::GetSidSubAuthorityCount(sid);
  for(int i = 0; i < sub_auth_count; ++i)
    base::StringAppendF(&sid_string, L"-%lu", *::GetSidSubAuthority(sid, i));
#endif

  // Get the contents of the string as a bunch of bytes.
  return std::vector<uint8_t>(
           reinterpret_cast<uint8_t*>(&sid_string[0]),
           reinterpret_cast<uint8_t*>(&sid_string[sid_string.size()]));
}

}  // namespace

bool GetRawMachineId(std::vector<uint8_t>* sid_bytes, int* volume_id) {
  // Calculate the Windows SID.

  wchar_t computer_name[MAX_COMPUTERNAME_LENGTH + 1] = {0};
  DWORD size = mozilla::ArrayLength(computer_name);

  if (GetComputerNameW(computer_name, &size)) {
    char sid_buffer[SECURITY_MAX_SID_SIZE];
    SID* sid = reinterpret_cast<SID*>(sid_buffer);
    if (GetComputerSid(computer_name, sid, SECURITY_MAX_SID_SIZE)) {
      *sid_bytes = ConvertSidToBytes(sid);
    }
  }

  // Get the system drive volume serial number.
  *volume_id = 0;
  if (!GetSystemVolumeSerialNumber(volume_id)) {
    ASSERT_STRING("GetMachineId: Failed to retrieve volume serial number");
    *volume_id = 0;
  }

  return true;
}

}  // namespace rlz_lib