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 |