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