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 "remoting/host/sas_injector.h"
6 
7 #include <windows.h>
8 #include <sas.h>
9 
10 #include <memory>
11 #include <utility>
12 
13 #include "base/logging.h"
14 #include "base/macros.h"
15 #include "base/win/registry.h"
16 
17 namespace remoting {
18 
19 namespace {
20 
21 // The registry key and value holding the policy controlling software SAS
22 // generation.
23 const wchar_t kSystemPolicyKeyName[] =
24     L"Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System";
25 const wchar_t kSoftwareSasValueName[] = L"SoftwareSASGeneration";
26 
27 const DWORD kEnableSoftwareSasByServices = 1;
28 
29 // Toggles the default software SAS generation policy to enable SAS generation
30 // by services. Non-default policy is not changed.
31 class ScopedSoftwareSasPolicy {
32  public:
33   ScopedSoftwareSasPolicy();
34   ~ScopedSoftwareSasPolicy();
35 
36   bool Apply();
37 
38  private:
39   // The handle of the registry key were SoftwareSASGeneration policy is stored.
40   base::win::RegKey system_policy_;
41 
42   // True if the policy needs to be restored.
43   bool restore_policy_ = false;
44 
45   DISALLOW_COPY_AND_ASSIGN(ScopedSoftwareSasPolicy);
46 };
47 
48 ScopedSoftwareSasPolicy::ScopedSoftwareSasPolicy() = default;
49 
~ScopedSoftwareSasPolicy()50 ScopedSoftwareSasPolicy::~ScopedSoftwareSasPolicy() {
51   // Restore the default policy by deleting the value that we have set.
52   if (restore_policy_) {
53     LONG result = system_policy_.DeleteValue(kSoftwareSasValueName);
54     if (result != ERROR_SUCCESS) {
55       SetLastError(result);
56       PLOG(ERROR) << "Failed to restore the software SAS generation policy";
57     }
58   }
59 }
60 
Apply()61 bool ScopedSoftwareSasPolicy::Apply() {
62   // Query the currently set SoftwareSASGeneration policy.
63   LONG result = system_policy_.Open(HKEY_LOCAL_MACHINE,
64                                     kSystemPolicyKeyName,
65                                     KEY_QUERY_VALUE | KEY_SET_VALUE |
66                                         KEY_WOW64_64KEY);
67   if (result != ERROR_SUCCESS) {
68     SetLastError(result);
69     PLOG(ERROR) << "Failed to open 'HKLM\\" << kSystemPolicyKeyName << "'";
70     return false;
71   }
72 
73   bool custom_policy = system_policy_.HasValue(kSoftwareSasValueName);
74 
75   // Override the default policy (i.e. there is no value in the registry) only.
76   if (!custom_policy) {
77     result = system_policy_.WriteValue(kSoftwareSasValueName,
78                                        kEnableSoftwareSasByServices);
79     if (result != ERROR_SUCCESS) {
80       SetLastError(result);
81       PLOG(ERROR) << "Failed to enable software SAS generation by services";
82       return false;
83     } else {
84       restore_policy_ = true;
85     }
86   }
87 
88   return true;
89 }
90 
91 } // namespace
92 
93 // Sends Secure Attention Sequence.  Checks the current policy before sending.
94 class SasInjectorWin : public SasInjector {
95  public:
96   SasInjectorWin();
97   ~SasInjectorWin() override;
98 
99   // SasInjector implementation.
100   bool InjectSas() override;
101 
102  private:
103   DISALLOW_COPY_AND_ASSIGN(SasInjectorWin);
104 };
105 
106 SasInjectorWin::SasInjectorWin() = default;
107 
108 SasInjectorWin::~SasInjectorWin() = default;
109 
InjectSas()110 bool SasInjectorWin::InjectSas() {
111   // Enable software SAS generation by services and send SAS. SAS can still fail
112   // if the policy does not allow services to generate software SAS.
113   ScopedSoftwareSasPolicy enable_sas;
114   if (!enable_sas.Apply()) {
115     return false;
116   }
117 
118   SendSAS(/*AsUser=*/FALSE);
119   return true;
120 }
121 
Create()122 std::unique_ptr<SasInjector> SasInjector::Create() {
123   return std::make_unique<SasInjectorWin>();
124 }
125 
126 } // namespace remoting
127