Home | History | Annotate | Download | only in permissions
      1 // Copyright 2013 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/common/extensions/permissions/socket_permission_entry.h"
      6 
      7 #include <cstdlib>
      8 #include <sstream>
      9 #include <vector>
     10 
     11 #include "base/logging.h"
     12 #include "base/memory/scoped_ptr.h"
     13 #include "base/strings/string_number_conversions.h"
     14 #include "base/strings/string_split.h"
     15 #include "base/strings/string_util.h"
     16 #include "chrome/common/extensions/permissions/socket_permission.h"
     17 #include "extensions/common/permissions/api_permission.h"
     18 #include "url/url_canon.h"
     19 
     20 namespace {
     21 
     22 using content::SocketPermissionRequest;
     23 
     24 const char kColon = ':';
     25 const char kDot = '.';
     26 const char kWildcard[] = "*";
     27 const int kWildcardPortNumber = 0;
     28 const int kInvalidPort = -1;
     29 
     30 bool StartsOrEndsWithWhitespace(const std::string& str) {
     31   if (str.find_first_not_of(base::kWhitespaceASCII) != 0)
     32     return true;
     33   if (str.find_last_not_of(base::kWhitespaceASCII) != str.length() - 1)
     34     return true;
     35   return false;
     36 }
     37 
     38 }  // namespace
     39 
     40 namespace extensions {
     41 
     42 SocketPermissionEntry::SocketPermissionEntry()
     43   : pattern_(SocketPermissionRequest::NONE, std::string(), kInvalidPort),
     44     match_subdomains_(false) {
     45 }
     46 
     47 SocketPermissionEntry::~SocketPermissionEntry() {}
     48 
     49 bool SocketPermissionEntry::operator<(const SocketPermissionEntry& rhs) const {
     50   if (pattern_.type < rhs.pattern_.type)
     51     return true;
     52   if (pattern_.type > rhs.pattern_.type)
     53     return false;
     54 
     55   if (pattern_.host < rhs.pattern_.host)
     56     return true;
     57   if (pattern_.host > rhs.pattern_.host)
     58     return false;
     59 
     60   if (match_subdomains_ < rhs.match_subdomains_)
     61     return true;
     62   if (match_subdomains_ > rhs.match_subdomains_)
     63     return false;
     64 
     65   if (pattern_.port < rhs.pattern_.port)
     66     return true;
     67   return false;
     68 }
     69 
     70 bool SocketPermissionEntry::operator==(const SocketPermissionEntry& rhs) const {
     71   return (pattern_.type == rhs.pattern_.type) &&
     72          (pattern_.host == rhs.pattern_.host) &&
     73          (match_subdomains_ == rhs.match_subdomains_) &&
     74          (pattern_.port == rhs.pattern_.port);
     75 }
     76 
     77 bool SocketPermissionEntry::Check(
     78     const content::SocketPermissionRequest& request) const {
     79   if (pattern_.type != request.type)
     80     return false;
     81 
     82   std::string lhost = StringToLowerASCII(request.host);
     83   if (pattern_.host != lhost) {
     84     if (!match_subdomains_)
     85       return false;
     86 
     87     if (!pattern_.host.empty()) {
     88       // Do not wildcard part of IP address.
     89       url_parse::Component component(0, lhost.length());
     90       url_canon::RawCanonOutputT<char, 128> ignored_output;
     91       url_canon::CanonHostInfo host_info;
     92       url_canon::CanonicalizeIPAddress(lhost.c_str(), component,
     93                                        &ignored_output, &host_info);
     94       if (host_info.IsIPAddress())
     95         return false;
     96 
     97       // host should equal one or more chars + "." +  host_.
     98       int i = lhost.length() - pattern_.host.length();
     99       if (i < 2)
    100         return false;
    101 
    102       if (lhost.compare(i, pattern_.host.length(), pattern_.host) != 0)
    103         return false;
    104 
    105       if (lhost[i - 1] != kDot)
    106         return false;
    107     }
    108   }
    109 
    110   if (pattern_.port != request.port && pattern_.port != kWildcardPortNumber)
    111     return false;
    112 
    113   return true;
    114 }
    115 
    116 SocketPermissionEntry::HostType SocketPermissionEntry::GetHostType() const {
    117   return pattern_.host.empty() ? SocketPermissionEntry::ANY_HOST :
    118          match_subdomains_     ? SocketPermissionEntry::HOSTS_IN_DOMAINS :
    119                                  SocketPermissionEntry::SPECIFIC_HOSTS;
    120 }
    121 
    122 bool SocketPermissionEntry::IsAddressBoundType() const {
    123   return pattern_.type == SocketPermissionRequest::TCP_CONNECT ||
    124       pattern_.type == SocketPermissionRequest::TCP_LISTEN ||
    125       pattern_.type == SocketPermissionRequest::UDP_BIND ||
    126       pattern_.type == SocketPermissionRequest::UDP_SEND_TO;
    127 }
    128 
    129 // static
    130 bool SocketPermissionEntry::ParseHostPattern(
    131     SocketPermissionRequest::OperationType type,
    132     const std::string& pattern,
    133     SocketPermissionEntry* entry) {
    134   std::vector<std::string> tokens;
    135   base::SplitStringDontTrim(pattern, kColon, &tokens);
    136   return ParseHostPattern(type, tokens, entry);
    137 }
    138 
    139 // static
    140 bool SocketPermissionEntry::ParseHostPattern(
    141     SocketPermissionRequest::OperationType type,
    142     const std::vector<std::string>& pattern_tokens,
    143     SocketPermissionEntry* entry) {
    144 
    145   SocketPermissionEntry result;
    146 
    147   if (type == SocketPermissionRequest::NONE)
    148     return false;
    149 
    150   if (pattern_tokens.size() > 2)
    151     return false;
    152 
    153   result.pattern_.type = type;
    154   result.pattern_.port = kWildcardPortNumber;
    155   result.match_subdomains_ = true;
    156 
    157   if (pattern_tokens.size() == 0) {
    158     *entry = result;
    159     return true;
    160   }
    161 
    162     // Return an error if address is specified for permissions that don't
    163     // need it (such as 'resolve-host').
    164     if (!result.IsAddressBoundType())
    165       return false;
    166 
    167   result.pattern_.host = pattern_tokens[0];
    168   if (!result.pattern_.host.empty()) {
    169     if (StartsOrEndsWithWhitespace(result.pattern_.host))
    170       return false;
    171     result.pattern_.host = StringToLowerASCII(result.pattern_.host);
    172 
    173     // The first component can optionally be '*' to match all subdomains.
    174     std::vector<std::string> host_components;
    175     base::SplitString(result.pattern_.host, kDot, &host_components);
    176     DCHECK(!host_components.empty());
    177 
    178     if (host_components[0] == kWildcard || host_components[0].empty()) {
    179       host_components.erase(host_components.begin(),
    180                             host_components.begin() + 1);
    181     } else {
    182       result.match_subdomains_ = false;
    183     }
    184     result.pattern_.host = JoinString(host_components, kDot);
    185   }
    186 
    187   if (pattern_tokens.size() == 1 ||
    188       pattern_tokens[1].empty() ||
    189       pattern_tokens[1] == kWildcard) {
    190     *entry = result;
    191     return true;
    192   }
    193 
    194   if (StartsOrEndsWithWhitespace(pattern_tokens[1]))
    195     return false;
    196 
    197   if (!base::StringToInt(pattern_tokens[1], &result.pattern_.port) ||
    198       result.pattern_.port < 1 || result.pattern_.port > 65535)
    199     return false;
    200 
    201   *entry = result;
    202   return true;
    203 }
    204 
    205 std::string SocketPermissionEntry::GetHostPatternAsString() const {
    206   std::string result;
    207 
    208   if (!IsAddressBoundType())
    209     return result;
    210 
    211   if (match_subdomains()) {
    212     result.append(kWildcard);
    213     if (!pattern_.host.empty())
    214       result.append(1, kDot).append(pattern_.host);
    215   } else {
    216      result.append(pattern_.host);
    217   }
    218 
    219   if (pattern_.port == kWildcardPortNumber)
    220     result.append(1, kColon).append(kWildcard);
    221   else
    222     result.append(1, kColon).append(base::IntToString(pattern_.port));
    223 
    224   return result;
    225 }
    226 
    227 }  // namespace extensions
    228