• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
StartsOrEndsWithWhitespace(const std::string & str)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 
SocketPermissionEntry()42 SocketPermissionEntry::SocketPermissionEntry()
43   : pattern_(SocketPermissionRequest::NONE, std::string(), kInvalidPort),
44     match_subdomains_(false) {
45 }
46 
~SocketPermissionEntry()47 SocketPermissionEntry::~SocketPermissionEntry() {}
48 
operator <(const SocketPermissionEntry & rhs) const49 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 
operator ==(const SocketPermissionEntry & rhs) const70 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 
Check(const content::SocketPermissionRequest & request) const77 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 
GetHostType() const116 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 
IsAddressBoundType() const122 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
ParseHostPattern(SocketPermissionRequest::OperationType type,const std::string & pattern,SocketPermissionEntry * entry)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
ParseHostPattern(SocketPermissionRequest::OperationType type,const std::vector<std::string> & pattern_tokens,SocketPermissionEntry * entry)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 
GetHostPatternAsString() const205 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