• 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 "chrome/browser/ui/network_profile_bubble.h"
6 
7 #include <windows.h>
8 
9 #include <wtsapi32.h>
10 // Make sure we link the wtsapi lib file in.
11 #pragma comment(lib, "wtsapi32.lib")
12 
13 #include "base/bind.h"
14 #include "base/command_line.h"
15 #include "base/file_util.h"
16 #include "base/files/file_path.h"
17 #include "base/logging.h"
18 #include "base/metrics/histogram.h"
19 #include "base/prefs/pref_service.h"
20 #include "base/time/time.h"
21 #include "chrome/browser/browser_process.h"
22 #include "chrome/browser/profiles/profile.h"
23 #include "chrome/browser/ui/browser_finder.h"
24 #include "chrome/browser/ui/browser_list.h"
25 #include "chrome/browser/ui/browser_list_observer.h"
26 #include "chrome/common/chrome_switches.h"
27 #include "chrome/common/pref_names.h"
28 #include "components/pref_registry/pref_registry_syncable.h"
29 #include "content/public/browser/browser_thread.h"
30 
31 namespace {
32 
33 // The duration of the silent period before we start nagging the user again.
34 const int kSilenceDurationDays = 100;
35 
36 // The number of warnings to be shown on consequtive starts of Chrome before the
37 // silent period starts.
38 const int kMaxWarnings = 2;
39 
40 // Implementation of chrome::BrowserListObserver used to wait for a browser
41 // window.
42 class BrowserListObserver : public chrome::BrowserListObserver {
43  private:
44   virtual ~BrowserListObserver();
45 
46   // Overridden from chrome::BrowserListObserver:
47   virtual void OnBrowserAdded(Browser* browser) OVERRIDE;
48   virtual void OnBrowserRemoved(Browser* browser) OVERRIDE;
49   virtual void OnBrowserSetLastActive(Browser* browser) OVERRIDE;
50 };
51 
~BrowserListObserver()52 BrowserListObserver::~BrowserListObserver() {
53 }
54 
OnBrowserAdded(Browser * browser)55 void BrowserListObserver::OnBrowserAdded(Browser* browser) {
56 }
57 
OnBrowserRemoved(Browser * browser)58 void BrowserListObserver::OnBrowserRemoved(Browser* browser) {
59 }
60 
OnBrowserSetLastActive(Browser * browser)61 void BrowserListObserver::OnBrowserSetLastActive(Browser* browser) {
62   NetworkProfileBubble::ShowNotification(browser);
63   // No need to observe anymore.
64   BrowserList::RemoveObserver(this);
65   delete this;
66 }
67 
68 // The name of the UMA histogram collecting our stats.
69 const char kMetricNetworkedProfileCheck[] = "NetworkedProfile.Check";
70 
71 }  // namespace
72 
73 // static
74 bool NetworkProfileBubble::notification_shown_ = false;
75 
76 // static
ShouldCheckNetworkProfile(Profile * profile)77 bool NetworkProfileBubble::ShouldCheckNetworkProfile(Profile* profile) {
78   PrefService* prefs = profile->GetPrefs();
79   if (prefs->GetInteger(prefs::kNetworkProfileWarningsLeft))
80     return !notification_shown_;
81   int64 last_check = prefs->GetInt64(prefs::kNetworkProfileLastWarningTime);
82   base::TimeDelta time_since_last_check =
83       base::Time::Now() - base::Time::FromTimeT(last_check);
84   if (time_since_last_check.InDays() > kSilenceDurationDays) {
85     prefs->SetInteger(prefs::kNetworkProfileWarningsLeft, kMaxWarnings);
86     return !notification_shown_;
87   }
88   return false;
89 }
90 
91 // static
CheckNetworkProfile(const base::FilePath & profile_folder)92 void NetworkProfileBubble::CheckNetworkProfile(
93     const base::FilePath& profile_folder) {
94   DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
95   // On Windows notify the users if their profiles are located on a network
96   // share as we don't officially support this setup yet.
97   // However we don't want to bother users on Cytrix setups as those have no
98   // real choice and their admins must be well aware of the risks associated.
99   // Also the command line flag --no-network-profile-warning can stop this
100   // warning from popping up. In this case we can skip the check to make the
101   // start faster.
102   // Collect a lot of stats along the way to see which cases do occur in the
103   // wild often enough.
104   if (CommandLine::ForCurrentProcess()->HasSwitch(
105           switches::kNoNetworkProfileWarning)) {
106     RecordUmaEvent(METRIC_CHECK_SUPPRESSED);
107     return;
108   }
109 
110   LPWSTR buffer = NULL;
111   DWORD buffer_length = 0;
112   // Checking for RDP is cheaper than checking for a network drive so do this
113   // one first.
114   if (!::WTSQuerySessionInformation(WTS_CURRENT_SERVER, WTS_CURRENT_SESSION,
115                                     WTSClientProtocolType,
116                                     &buffer, &buffer_length)) {
117     RecordUmaEvent(METRIC_CHECK_FAILED);
118     return;
119   }
120 
121   unsigned short* type = reinterpret_cast<unsigned short*>(buffer);
122   // We should warn the users if they have their profile on a network share only
123   // if running on a local session.
124   if (*type == WTS_PROTOCOL_TYPE_CONSOLE) {
125     bool profile_on_network = false;
126     if (!profile_folder.empty()) {
127       base::FilePath temp_file;
128       // Try to create some non-empty temp file in the profile dir and use
129       // it to check if there is a reparse-point free path to it.
130       if (base::CreateTemporaryFileInDir(profile_folder, &temp_file) &&
131           (base::WriteFile(temp_file, ".", 1) == 1)) {
132         base::FilePath normalized_temp_file;
133         if (!base::NormalizeFilePath(temp_file, &normalized_temp_file))
134           profile_on_network = true;
135       } else {
136         RecordUmaEvent(METRIC_CHECK_IO_FAILED);
137       }
138       base::DeleteFile(temp_file, false);
139     }
140     if (profile_on_network) {
141       RecordUmaEvent(METRIC_PROFILE_ON_NETWORK);
142       content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
143           base::Bind(&NotifyNetworkProfileDetected));
144     } else {
145       RecordUmaEvent(METRIC_PROFILE_NOT_ON_NETWORK);
146     }
147   } else {
148     RecordUmaEvent(METRIC_REMOTE_SESSION);
149   }
150 
151   ::WTSFreeMemory(buffer);
152 }
153 
154 // static
SetNotificationShown(bool shown)155 void NetworkProfileBubble::SetNotificationShown(bool shown) {
156   notification_shown_ = shown;
157 }
158 
159 // static
RegisterProfilePrefs(user_prefs::PrefRegistrySyncable * registry)160 void NetworkProfileBubble::RegisterProfilePrefs(
161     user_prefs::PrefRegistrySyncable* registry) {
162   registry->RegisterIntegerPref(
163       prefs::kNetworkProfileWarningsLeft,
164       kMaxWarnings,
165       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
166   registry->RegisterInt64Pref(
167       prefs::kNetworkProfileLastWarningTime,
168       0,
169       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
170 }
171 
172 // static
RecordUmaEvent(MetricNetworkedProfileCheck event)173 void NetworkProfileBubble::RecordUmaEvent(MetricNetworkedProfileCheck event) {
174   UMA_HISTOGRAM_ENUMERATION(kMetricNetworkedProfileCheck,
175                             event,
176                             METRIC_NETWORKED_PROFILE_CHECK_SIZE);
177 }
178 
179 // static
NotifyNetworkProfileDetected()180 void NetworkProfileBubble::NotifyNetworkProfileDetected() {
181   Browser* browser = chrome::FindLastActiveWithHostDesktopType(
182       chrome::GetActiveDesktop());
183 
184   if (browser)
185     ShowNotification(browser);
186   else
187     BrowserList::AddObserver(new BrowserListObserver());
188 }
189