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 36 PluginSelectionPolicy::PluginSelectionPolicy() 37 : init_from_file_finished_(false) { 38 } 39 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 48 bool PluginSelectionPolicy::Init() { 49 return InitFromFile(FilePath(kPluginSelectionPolicyFile)); 50 } 51 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 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 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