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