1 // Copyright (c) 2011 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/chromeos/plugin_selection_policy.h"
6
7 #include <algorithm>
8 #include <iostream>
9 #include <map>
10 #include <sstream>
11 #include <string>
12 #include <vector>
13
14 #include "base/auto_reset.h"
15 #include "base/file_path.h"
16 #include "base/file_util.h"
17 #include "base/logging.h"
18 #include "base/string_util.h"
19 #include "content/browser/browser_thread.h"
20 #include "googleurl/src/gurl.h"
21
22 #if !defined(OS_CHROMEOS)
23 #error This file is meant to be compiled on ChromeOS only.
24 #endif
25
26 using std::vector;
27 using std::string;
28 using std::pair;
29 using std::map;
30
31 namespace chromeos {
32
33 static const char kPluginSelectionPolicyFile[] =
34 "/usr/share/chromeos-assets/flash/plugin_policy";
35
PluginSelectionPolicy()36 PluginSelectionPolicy::PluginSelectionPolicy()
37 : init_from_file_finished_(false) {
38 }
39
StartInit()40 void PluginSelectionPolicy::StartInit() {
41 // Initialize the policy on the FILE thread, since it reads from a
42 // policy file.
43 BrowserThread::PostTask(
44 BrowserThread::FILE, FROM_HERE,
45 NewRunnableMethod(this, &chromeos::PluginSelectionPolicy::Init));
46 }
47
Init()48 bool PluginSelectionPolicy::Init() {
49 return InitFromFile(FilePath(kPluginSelectionPolicyFile));
50 }
51
InitFromFile(const FilePath & policy_file)52 bool PluginSelectionPolicy::InitFromFile(const FilePath& policy_file) {
53 // This must always be called from the FILE thread.
54 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
55
56 string data;
57 // This should be a really small file, so we're OK with just
58 // slurping it.
59 if (!file_util::ReadFileToString(policy_file, &data)) {
60 LOG(ERROR) << "Unable to read plugin policy file \""
61 << policy_file.value() << "\".";
62 init_from_file_finished_ = true;
63 return false;
64 }
65
66 std::istringstream input_stream(data);
67 string line;
68 map<string, Policy> policies;
69 Policy policy;
70 string last_plugin;
71
72 while (std::getline(input_stream, line)) {
73 // Strip comments.
74 string::size_type pos = line.find("#");
75 if (pos != string::npos) {
76 line = line.substr(0, pos);
77 }
78 TrimWhitespaceASCII(line, TRIM_ALL, &line);
79 if (line.find("allow") == 0) {
80 // Has to be preceeded by a "plugin" statement.
81 if (last_plugin.empty()) {
82 LOG(ERROR) << "Plugin policy file error: 'allow' out of context.";
83 init_from_file_finished_ = true;
84 return false;
85 }
86 line = line.substr(5);
87 TrimWhitespaceASCII(line, TRIM_ALL, &line);
88 line = StringToLowerASCII(line);
89 policy.push_back(make_pair(true, line));
90 }
91 if (line.find("deny") == 0) {
92 // Has to be preceeded by a "plugin" statement.
93 if (last_plugin.empty()) {
94 LOG(ERROR) << "Plugin policy file error: 'deny' out of context.";
95 init_from_file_finished_ = true;
96 return false;
97 }
98 line = line.substr(4);
99 TrimWhitespaceASCII(line, TRIM_ALL, &line);
100 line = StringToLowerASCII(line);
101 policy.push_back(make_pair(false, line));
102 }
103 if (line.find("plugin") == 0) {
104 line = line.substr(6);
105 TrimWhitespaceASCII(line, TRIM_ALL, &line);
106 if (!policy.empty() && !last_plugin.empty())
107 policies.insert(make_pair(last_plugin, policy));
108 last_plugin = line;
109 policy.clear();
110 }
111 }
112
113 if (!last_plugin.empty())
114 policies.insert(make_pair(last_plugin, policy));
115
116 policies_.swap(policies);
117 init_from_file_finished_ = true;
118 return true;
119 }
120
FindFirstAllowed(const GURL & url,const std::vector<webkit::npapi::WebPluginInfo> & info)121 int PluginSelectionPolicy::FindFirstAllowed(
122 const GURL& url,
123 const std::vector<webkit::npapi::WebPluginInfo>& info) {
124 for (std::vector<webkit::npapi::WebPluginInfo>::size_type i = 0;
125 i < info.size(); ++i) {
126 if (IsAllowed(url, info[i].path))
127 return i;
128 }
129 return -1;
130 }
131
IsAllowed(const GURL & url,const FilePath & path)132 bool PluginSelectionPolicy::IsAllowed(const GURL& url,
133 const FilePath& path) {
134 // This must always be called from the FILE thread, to be sure
135 // initialization doesn't happen at the same time.
136 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
137
138 // Make sure that we notice if this starts being called before
139 // initialization is complete. Right now it is guaranteed only by
140 // the startup order and the fact that InitFromFile runs on the FILE
141 // thread too.
142 DCHECK(init_from_file_finished_)
143 << "Tried to check policy before policy is initialized.";
144
145 string name = path.BaseName().value();
146
147 PolicyMap::iterator policy_iter = policies_.find(name);
148 if (policy_iter != policies_.end()) {
149 Policy& policy(policy_iter->second);
150
151 // We deny by default. (equivalent to "deny" at the top of the section)
152 bool allow = false;
153
154 for (Policy::iterator iter = policy.begin(); iter != policy.end(); ++iter) {
155 bool policy_allow = iter->first;
156 string& policy_domain = iter->second;
157 if (policy_domain.empty() || url.DomainIs(policy_domain.c_str(),
158 policy_domain.size())) {
159 allow = policy_allow;
160 }
161 }
162 return allow;
163 }
164
165 // If it's not in the policy file, then we assume it's OK to allow
166 // it.
167 return true;
168 }
169
170 } // namespace chromeos
171