| OLD | NEW |
| (Empty) |
| 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 | |
| OLD | NEW |