Line data Source code
1 : /* This Source Code Form is subject to the terms of the Mozilla Public
2 : * License, v. 2.0. If a copy of the MPL was not distributed with this
3 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 :
5 : #include "mozilla/net/HttpAuthUtils.h"
6 : #include "mozilla/Tokenizer.h"
7 : #include "nsIPrefService.h"
8 : #include "nsIURI.h"
9 : #include "nsNetUtil.h"
10 : #include "nsUnicharUtils.h"
11 :
12 : namespace mozilla {
13 : namespace net {
14 : namespace auth {
15 :
16 : namespace detail {
17 :
18 : bool
19 0 : MatchesBaseURI(const nsACString& matchScheme,
20 : const nsACString& matchHost,
21 : int32_t matchPort,
22 : nsDependentCSubstring const& url)
23 : {
24 : // check if scheme://host:port matches baseURI
25 :
26 : // parse the base URI
27 0 : mozilla::Tokenizer t(url);
28 0 : mozilla::Tokenizer::Token token;
29 :
30 0 : t.SkipWhites();
31 :
32 : // We don't know if the url to check against starts with scheme
33 : // or a host name. Start recording here.
34 0 : t.Record();
35 :
36 0 : mozilla::Unused << t.Next(token);
37 :
38 : // The ipv6 literals MUST be enclosed with [] in the preference.
39 0 : bool ipv6 = false;
40 0 : if (token.Equals(mozilla::Tokenizer::Token::Char('['))) {
41 0 : nsDependentCSubstring ipv6BareLiteral;
42 0 : if (!t.ReadUntil(mozilla::Tokenizer::Token::Char(']'), ipv6BareLiteral)) {
43 : // Broken ipv6 literal
44 0 : return false;
45 : }
46 :
47 0 : nsDependentCSubstring ipv6Literal;
48 0 : t.Claim(ipv6Literal, mozilla::Tokenizer::INCLUDE_LAST);
49 0 : if (!matchHost.Equals(ipv6Literal, nsCaseInsensitiveUTF8StringComparator()) &&
50 0 : !matchHost.Equals(ipv6BareLiteral, nsCaseInsensitiveUTF8StringComparator())) {
51 0 : return false;
52 : }
53 :
54 0 : ipv6 = true;
55 0 : } else if (t.CheckChar(':') && t.CheckChar('/') && t.CheckChar('/')) {
56 0 : if (!matchScheme.Equals(token.Fragment())) {
57 0 : return false;
58 : }
59 : // Re-start recording the hostname from the point after scheme://.
60 0 : t.Record();
61 : }
62 :
63 0 : while (t.Next(token)) {
64 0 : bool eof = token.Equals(mozilla::Tokenizer::Token::EndOfFile());
65 0 : bool port = token.Equals(mozilla::Tokenizer::Token::Char(':'));
66 :
67 0 : if (eof || port) {
68 0 : if (!ipv6) { // Match already performed above.
69 0 : nsDependentCSubstring hostName;
70 0 : t.Claim(hostName);
71 :
72 : // An empty hostname means to accept everything for the schema
73 0 : if (!hostName.IsEmpty()) {
74 : /*
75 : host: bar.com foo.bar.com foobar.com foo.bar.com bar.com
76 : pref: bar.com bar.com bar.com .bar.com .bar.com
77 : result: accept accept reject accept reject
78 : */
79 0 : if (!StringEndsWith(matchHost, hostName, nsCaseInsensitiveUTF8StringComparator())) {
80 0 : return false;
81 : }
82 0 : if (matchHost.Length() > hostName.Length() &&
83 0 : matchHost[matchHost.Length() - hostName.Length() - 1] != '.' &&
84 0 : hostName[0] != '.') {
85 0 : return false;
86 : }
87 : }
88 : }
89 :
90 0 : if (port) {
91 : uint16_t portNumber;
92 0 : if (!t.ReadInteger(&portNumber)) {
93 : // Missing port number
94 0 : return false;
95 : }
96 0 : if (matchPort != portNumber) {
97 0 : return false;
98 : }
99 0 : if (!t.CheckEOF()) {
100 0 : return false;
101 : }
102 0 : }
103 0 : } else if (ipv6) {
104 : // After an ipv6 literal there can only be EOF or :port. Everything else
105 : // must be treated as non-match/broken input.
106 0 : return false;
107 : }
108 : }
109 :
110 : // All negative checks has passed positively.
111 0 : return true;
112 : }
113 :
114 : } // namespace detail
115 :
116 :
117 : bool
118 0 : URIMatchesPrefPattern(nsIURI *uri, const char *pref)
119 : {
120 0 : nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
121 0 : if (!prefs) {
122 0 : return false;
123 : }
124 :
125 0 : nsAutoCString scheme, host;
126 : int32_t port;
127 :
128 0 : if (NS_FAILED(uri->GetScheme(scheme))) {
129 0 : return false;
130 : }
131 0 : if (NS_FAILED(uri->GetAsciiHost(host))) {
132 0 : return false;
133 : }
134 :
135 0 : port = NS_GetRealPort(uri);
136 0 : if (port == -1) {
137 0 : return false;
138 : }
139 :
140 : char *hostList;
141 0 : if (NS_FAILED(prefs->GetCharPref(pref, &hostList)) || !hostList) {
142 0 : return false;
143 : }
144 :
145 0 : struct FreePolicy { void operator()(void* p) { free(p); } };
146 0 : mozilla::UniquePtr<char[], FreePolicy> hostListScope;
147 0 : hostListScope.reset(hostList);
148 :
149 : // pseudo-BNF
150 : // ----------
151 : //
152 : // url-list base-url ( base-url "," LWS )*
153 : // base-url ( scheme-part | host-part | scheme-part host-part )
154 : // scheme-part scheme "://"
155 : // host-part host [":" port]
156 : //
157 : // for example:
158 : // "https://, http://office.foo.com"
159 : //
160 :
161 0 : mozilla::Tokenizer t(hostList);
162 0 : while (!t.CheckEOF()) {
163 0 : t.SkipWhites();
164 0 : nsDependentCSubstring url;
165 0 : mozilla::Unused << t.ReadUntil(mozilla::Tokenizer::Token::Char(','), url);
166 0 : if (url.IsEmpty()) {
167 0 : continue;
168 : }
169 0 : if (detail::MatchesBaseURI(scheme, host, port, url)) {
170 0 : return true;
171 : }
172 : }
173 :
174 0 : return false;
175 : }
176 :
177 : } // namespace auth
178 : } // namespace net
179 : } // namespace mozilla
|