Home | History | Annotate | Download | only in chromeos
      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