• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include "config.h"
30 #include "modules/webdatabase/DatabaseAuthorizer.h"
31 
32 #include "wtf/PassRefPtr.h"
33 
34 namespace blink {
35 
create(const String & databaseInfoTableName)36 PassRefPtrWillBeRawPtr<DatabaseAuthorizer> DatabaseAuthorizer::create(const String& databaseInfoTableName)
37 {
38     return adoptRefWillBeNoop(new DatabaseAuthorizer(databaseInfoTableName));
39 }
40 
DatabaseAuthorizer(const String & databaseInfoTableName)41 DatabaseAuthorizer::DatabaseAuthorizer(const String& databaseInfoTableName)
42     : m_securityEnabled(false)
43     , m_databaseInfoTableName(databaseInfoTableName)
44 {
45     reset();
46     addWhitelistedFunctions();
47 }
48 
reset()49 void DatabaseAuthorizer::reset()
50 {
51     m_lastActionWasInsert = false;
52     m_lastActionChangedDatabase = false;
53     m_permissions = ReadWriteMask;
54 }
55 
resetDeletes()56 void DatabaseAuthorizer::resetDeletes()
57 {
58     m_hadDeletes = false;
59 }
60 
addWhitelistedFunctions()61 void DatabaseAuthorizer::addWhitelistedFunctions()
62 {
63     // SQLite functions used to help implement some operations
64     // ALTER TABLE helpers
65     m_whitelistedFunctions.add("sqlite_rename_table");
66     m_whitelistedFunctions.add("sqlite_rename_trigger");
67     // GLOB helpers
68     m_whitelistedFunctions.add("glob");
69 
70     // SQLite core functions
71     m_whitelistedFunctions.add("abs");
72     m_whitelistedFunctions.add("changes");
73     m_whitelistedFunctions.add("coalesce");
74     m_whitelistedFunctions.add("glob");
75     m_whitelistedFunctions.add("ifnull");
76     m_whitelistedFunctions.add("hex");
77     m_whitelistedFunctions.add("last_insert_rowid");
78     m_whitelistedFunctions.add("length");
79     m_whitelistedFunctions.add("like");
80     m_whitelistedFunctions.add("lower");
81     m_whitelistedFunctions.add("ltrim");
82     m_whitelistedFunctions.add("max");
83     m_whitelistedFunctions.add("min");
84     m_whitelistedFunctions.add("nullif");
85     m_whitelistedFunctions.add("quote");
86     m_whitelistedFunctions.add("replace");
87     m_whitelistedFunctions.add("round");
88     m_whitelistedFunctions.add("rtrim");
89     m_whitelistedFunctions.add("soundex");
90     m_whitelistedFunctions.add("sqlite_source_id");
91     m_whitelistedFunctions.add("sqlite_version");
92     m_whitelistedFunctions.add("substr");
93     m_whitelistedFunctions.add("total_changes");
94     m_whitelistedFunctions.add("trim");
95     m_whitelistedFunctions.add("typeof");
96     m_whitelistedFunctions.add("upper");
97     m_whitelistedFunctions.add("zeroblob");
98 
99     // SQLite date and time functions
100     m_whitelistedFunctions.add("date");
101     m_whitelistedFunctions.add("time");
102     m_whitelistedFunctions.add("datetime");
103     m_whitelistedFunctions.add("julianday");
104     m_whitelistedFunctions.add("strftime");
105 
106     // SQLite aggregate functions
107     // max() and min() are already in the list
108     m_whitelistedFunctions.add("avg");
109     m_whitelistedFunctions.add("count");
110     m_whitelistedFunctions.add("group_concat");
111     m_whitelistedFunctions.add("sum");
112     m_whitelistedFunctions.add("total");
113 
114     // SQLite FTS functions
115     m_whitelistedFunctions.add("match");
116     m_whitelistedFunctions.add("snippet");
117     m_whitelistedFunctions.add("offsets");
118     m_whitelistedFunctions.add("optimize");
119 
120     // SQLite ICU functions
121     // like(), lower() and upper() are already in the list
122     m_whitelistedFunctions.add("regexp");
123 }
124 
createTable(const String & tableName)125 int DatabaseAuthorizer::createTable(const String& tableName)
126 {
127     if (!allowWrite())
128         return SQLAuthDeny;
129 
130     m_lastActionChangedDatabase = true;
131     return denyBasedOnTableName(tableName);
132 }
133 
createTempTable(const String & tableName)134 int DatabaseAuthorizer::createTempTable(const String& tableName)
135 {
136     // SQLITE_CREATE_TEMP_TABLE results in a UPDATE operation, which is not
137     // allowed in read-only transactions or private browsing, so we might as
138     // well disallow SQLITE_CREATE_TEMP_TABLE in these cases
139     if (!allowWrite())
140         return SQLAuthDeny;
141 
142     return denyBasedOnTableName(tableName);
143 }
144 
dropTable(const String & tableName)145 int DatabaseAuthorizer::dropTable(const String& tableName)
146 {
147     if (!allowWrite())
148         return SQLAuthDeny;
149 
150     return updateDeletesBasedOnTableName(tableName);
151 }
152 
dropTempTable(const String & tableName)153 int DatabaseAuthorizer::dropTempTable(const String& tableName)
154 {
155     // SQLITE_DROP_TEMP_TABLE results in a DELETE operation, which is not
156     // allowed in read-only transactions or private browsing, so we might as
157     // well disallow SQLITE_DROP_TEMP_TABLE in these cases
158     if (!allowWrite())
159         return SQLAuthDeny;
160 
161     return updateDeletesBasedOnTableName(tableName);
162 }
163 
allowAlterTable(const String &,const String & tableName)164 int DatabaseAuthorizer::allowAlterTable(const String&, const String& tableName)
165 {
166     if (!allowWrite())
167         return SQLAuthDeny;
168 
169     m_lastActionChangedDatabase = true;
170     return denyBasedOnTableName(tableName);
171 }
172 
createIndex(const String &,const String & tableName)173 int DatabaseAuthorizer::createIndex(const String&, const String& tableName)
174 {
175     if (!allowWrite())
176         return SQLAuthDeny;
177 
178     m_lastActionChangedDatabase = true;
179     return denyBasedOnTableName(tableName);
180 }
181 
createTempIndex(const String &,const String & tableName)182 int DatabaseAuthorizer::createTempIndex(const String&, const String& tableName)
183 {
184     // SQLITE_CREATE_TEMP_INDEX should result in a UPDATE or INSERT operation,
185     // which is not allowed in read-only transactions or private browsing,
186     // so we might as well disallow SQLITE_CREATE_TEMP_INDEX in these cases
187     if (!allowWrite())
188         return SQLAuthDeny;
189 
190     return denyBasedOnTableName(tableName);
191 }
192 
dropIndex(const String &,const String & tableName)193 int DatabaseAuthorizer::dropIndex(const String&, const String& tableName)
194 {
195     if (!allowWrite())
196         return SQLAuthDeny;
197 
198     return updateDeletesBasedOnTableName(tableName);
199 }
200 
dropTempIndex(const String &,const String & tableName)201 int DatabaseAuthorizer::dropTempIndex(const String&, const String& tableName)
202 {
203     // SQLITE_DROP_TEMP_INDEX should result in a DELETE operation, which is
204     // not allowed in read-only transactions or private browsing, so we might
205     // as well disallow SQLITE_DROP_TEMP_INDEX in these cases
206     if (!allowWrite())
207         return SQLAuthDeny;
208 
209     return updateDeletesBasedOnTableName(tableName);
210 }
211 
createTrigger(const String &,const String & tableName)212 int DatabaseAuthorizer::createTrigger(const String&, const String& tableName)
213 {
214     if (!allowWrite())
215         return SQLAuthDeny;
216 
217     m_lastActionChangedDatabase = true;
218     return denyBasedOnTableName(tableName);
219 }
220 
createTempTrigger(const String &,const String & tableName)221 int DatabaseAuthorizer::createTempTrigger(const String&, const String& tableName)
222 {
223     // SQLITE_CREATE_TEMP_TRIGGER results in a INSERT operation, which is not
224     // allowed in read-only transactions or private browsing, so we might as
225     // well disallow SQLITE_CREATE_TEMP_TRIGGER in these cases
226     if (!allowWrite())
227         return SQLAuthDeny;
228 
229     return denyBasedOnTableName(tableName);
230 }
231 
dropTrigger(const String &,const String & tableName)232 int DatabaseAuthorizer::dropTrigger(const String&, const String& tableName)
233 {
234     if (!allowWrite())
235         return SQLAuthDeny;
236 
237     return updateDeletesBasedOnTableName(tableName);
238 }
239 
dropTempTrigger(const String &,const String & tableName)240 int DatabaseAuthorizer::dropTempTrigger(const String&, const String& tableName)
241 {
242     // SQLITE_DROP_TEMP_TRIGGER results in a DELETE operation, which is not
243     // allowed in read-only transactions or private browsing, so we might as
244     // well disallow SQLITE_DROP_TEMP_TRIGGER in these cases
245     if (!allowWrite())
246         return SQLAuthDeny;
247 
248     return updateDeletesBasedOnTableName(tableName);
249 }
250 
createView(const String &)251 int DatabaseAuthorizer::createView(const String&)
252 {
253     return (!allowWrite() ? SQLAuthDeny : SQLAuthAllow);
254 }
255 
createTempView(const String &)256 int DatabaseAuthorizer::createTempView(const String&)
257 {
258     // SQLITE_CREATE_TEMP_VIEW results in a UPDATE operation, which is not
259     // allowed in read-only transactions or private browsing, so we might as
260     // well disallow SQLITE_CREATE_TEMP_VIEW in these cases
261     return (!allowWrite() ? SQLAuthDeny : SQLAuthAllow);
262 }
263 
dropView(const String &)264 int DatabaseAuthorizer::dropView(const String&)
265 {
266     if (!allowWrite())
267         return SQLAuthDeny;
268 
269     m_hadDeletes = true;
270     return SQLAuthAllow;
271 }
272 
dropTempView(const String &)273 int DatabaseAuthorizer::dropTempView(const String&)
274 {
275     // SQLITE_DROP_TEMP_VIEW results in a DELETE operation, which is not
276     // allowed in read-only transactions or private browsing, so we might as
277     // well disallow SQLITE_DROP_TEMP_VIEW in these cases
278     if (!allowWrite())
279         return SQLAuthDeny;
280 
281     m_hadDeletes = true;
282     return SQLAuthAllow;
283 }
284 
createVTable(const String & tableName,const String & moduleName)285 int DatabaseAuthorizer::createVTable(const String& tableName, const String& moduleName)
286 {
287     if (!allowWrite())
288         return SQLAuthDeny;
289 
290     // Allow only the FTS3 extension
291     if (!equalIgnoringCase(moduleName, "fts3"))
292         return SQLAuthDeny;
293 
294     m_lastActionChangedDatabase = true;
295     return denyBasedOnTableName(tableName);
296 }
297 
dropVTable(const String & tableName,const String & moduleName)298 int DatabaseAuthorizer::dropVTable(const String& tableName, const String& moduleName)
299 {
300     if (!allowWrite())
301         return SQLAuthDeny;
302 
303     // Allow only the FTS3 extension
304     if (!equalIgnoringCase(moduleName, "fts3"))
305         return SQLAuthDeny;
306 
307     return updateDeletesBasedOnTableName(tableName);
308 }
309 
allowDelete(const String & tableName)310 int DatabaseAuthorizer::allowDelete(const String& tableName)
311 {
312     if (!allowWrite())
313         return SQLAuthDeny;
314 
315     return updateDeletesBasedOnTableName(tableName);
316 }
317 
allowInsert(const String & tableName)318 int DatabaseAuthorizer::allowInsert(const String& tableName)
319 {
320     if (!allowWrite())
321         return SQLAuthDeny;
322 
323     m_lastActionChangedDatabase = true;
324     m_lastActionWasInsert = true;
325     return denyBasedOnTableName(tableName);
326 }
327 
allowUpdate(const String & tableName,const String &)328 int DatabaseAuthorizer::allowUpdate(const String& tableName, const String&)
329 {
330     if (!allowWrite())
331         return SQLAuthDeny;
332 
333     m_lastActionChangedDatabase = true;
334     return denyBasedOnTableName(tableName);
335 }
336 
allowTransaction()337 int DatabaseAuthorizer::allowTransaction()
338 {
339     return m_securityEnabled ? SQLAuthDeny : SQLAuthAllow;
340 }
341 
allowRead(const String & tableName,const String &)342 int DatabaseAuthorizer::allowRead(const String& tableName, const String&)
343 {
344     if (m_permissions & NoAccessMask && m_securityEnabled)
345         return SQLAuthDeny;
346 
347     return denyBasedOnTableName(tableName);
348 }
349 
allowReindex(const String &)350 int DatabaseAuthorizer::allowReindex(const String&)
351 {
352     return (!allowWrite() ? SQLAuthDeny : SQLAuthAllow);
353 }
354 
allowAnalyze(const String & tableName)355 int DatabaseAuthorizer::allowAnalyze(const String& tableName)
356 {
357     return denyBasedOnTableName(tableName);
358 }
359 
allowPragma(const String &,const String &)360 int DatabaseAuthorizer::allowPragma(const String&, const String&)
361 {
362     return m_securityEnabled ? SQLAuthDeny : SQLAuthAllow;
363 }
364 
allowAttach(const String &)365 int DatabaseAuthorizer::allowAttach(const String&)
366 {
367     return m_securityEnabled ? SQLAuthDeny : SQLAuthAllow;
368 }
369 
allowDetach(const String &)370 int DatabaseAuthorizer::allowDetach(const String&)
371 {
372     return m_securityEnabled ? SQLAuthDeny : SQLAuthAllow;
373 }
374 
allowFunction(const String & functionName)375 int DatabaseAuthorizer::allowFunction(const String& functionName)
376 {
377     if (m_securityEnabled && !m_whitelistedFunctions.contains(functionName))
378         return SQLAuthDeny;
379 
380     return SQLAuthAllow;
381 }
382 
disable()383 void DatabaseAuthorizer::disable()
384 {
385     m_securityEnabled = false;
386 }
387 
enable()388 void DatabaseAuthorizer::enable()
389 {
390     m_securityEnabled = true;
391 }
392 
allowWrite()393 bool DatabaseAuthorizer::allowWrite()
394 {
395     return !(m_securityEnabled && (m_permissions & ReadOnlyMask || m_permissions & NoAccessMask));
396 }
397 
setPermissions(int permissions)398 void DatabaseAuthorizer::setPermissions(int permissions)
399 {
400     m_permissions = permissions;
401 }
402 
denyBasedOnTableName(const String & tableName) const403 int DatabaseAuthorizer::denyBasedOnTableName(const String& tableName) const
404 {
405     if (!m_securityEnabled)
406         return SQLAuthAllow;
407 
408     // Sadly, normal creates and drops end up affecting sqlite_master in an authorizer callback, so
409     // it will be tough to enforce all of the following policies
410     //if (equalIgnoringCase(tableName, "sqlite_master") || equalIgnoringCase(tableName, "sqlite_temp_master") ||
411     //    equalIgnoringCase(tableName, "sqlite_sequence") || equalIgnoringCase(tableName, Database::databaseInfoTableName()))
412     //        return SQLAuthDeny;
413 
414     if (equalIgnoringCase(tableName, m_databaseInfoTableName))
415         return SQLAuthDeny;
416 
417     return SQLAuthAllow;
418 }
419 
updateDeletesBasedOnTableName(const String & tableName)420 int DatabaseAuthorizer::updateDeletesBasedOnTableName(const String& tableName)
421 {
422     int allow = denyBasedOnTableName(tableName);
423     if (allow)
424         m_hadDeletes = true;
425     return allow;
426 }
427 
428 } // namespace blink
429