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 "DatabaseAuthorizer.h"
31 
32 #if ENABLE(DATABASE)
33 
34 #include "PlatformString.h"
35 #include <wtf/PassRefPtr.h>
36 
37 namespace WebCore {
38 
create(const String & databaseInfoTableName)39 PassRefPtr<DatabaseAuthorizer> DatabaseAuthorizer::create(const String& databaseInfoTableName)
40 {
41     return adoptRef(new DatabaseAuthorizer(databaseInfoTableName));
42 }
43 
DatabaseAuthorizer(const String & databaseInfoTableName)44 DatabaseAuthorizer::DatabaseAuthorizer(const String& databaseInfoTableName)
45     : m_securityEnabled(false)
46     , m_databaseInfoTableName(databaseInfoTableName)
47 {
48     reset();
49     addWhitelistedFunctions();
50 }
51 
reset()52 void DatabaseAuthorizer::reset()
53 {
54     m_lastActionWasInsert = false;
55     m_lastActionChangedDatabase = false;
56     m_permissions = ReadWriteMask;
57 }
58 
resetDeletes()59 void DatabaseAuthorizer::resetDeletes()
60 {
61     m_hadDeletes = false;
62 }
63 
addWhitelistedFunctions()64 void DatabaseAuthorizer::addWhitelistedFunctions()
65 {
66     // SQLite functions used to help implement some operations
67     // ALTER TABLE helpers
68     m_whitelistedFunctions.add("sqlite_rename_table");
69     m_whitelistedFunctions.add("sqlite_rename_trigger");
70     // GLOB helpers
71     m_whitelistedFunctions.add("glob");
72 
73     // SQLite core functions
74     m_whitelistedFunctions.add("abs");
75     m_whitelistedFunctions.add("changes");
76     m_whitelistedFunctions.add("coalesce");
77     m_whitelistedFunctions.add("glob");
78     m_whitelistedFunctions.add("ifnull");
79     m_whitelistedFunctions.add("hex");
80     m_whitelistedFunctions.add("last_insert_rowid");
81     m_whitelistedFunctions.add("length");
82     m_whitelistedFunctions.add("like");
83     m_whitelistedFunctions.add("lower");
84     m_whitelistedFunctions.add("ltrim");
85     m_whitelistedFunctions.add("max");
86     m_whitelistedFunctions.add("min");
87     m_whitelistedFunctions.add("nullif");
88     m_whitelistedFunctions.add("quote");
89     m_whitelistedFunctions.add("replace");
90     m_whitelistedFunctions.add("round");
91     m_whitelistedFunctions.add("rtrim");
92     m_whitelistedFunctions.add("soundex");
93     m_whitelistedFunctions.add("sqlite_source_id");
94     m_whitelistedFunctions.add("sqlite_version");
95     m_whitelistedFunctions.add("substr");
96     m_whitelistedFunctions.add("total_changes");
97     m_whitelistedFunctions.add("trim");
98     m_whitelistedFunctions.add("typeof");
99     m_whitelistedFunctions.add("upper");
100     m_whitelistedFunctions.add("zeroblob");
101 
102     // SQLite date and time functions
103     m_whitelistedFunctions.add("date");
104     m_whitelistedFunctions.add("time");
105     m_whitelistedFunctions.add("datetime");
106     m_whitelistedFunctions.add("julianday");
107     m_whitelistedFunctions.add("strftime");
108 
109     // SQLite aggregate functions
110     // max() and min() are already in the list
111     m_whitelistedFunctions.add("avg");
112     m_whitelistedFunctions.add("count");
113     m_whitelistedFunctions.add("group_concat");
114     m_whitelistedFunctions.add("sum");
115     m_whitelistedFunctions.add("total");
116 
117     // SQLite FTS functions
118     m_whitelistedFunctions.add("match");
119     m_whitelistedFunctions.add("snippet");
120     m_whitelistedFunctions.add("offsets");
121     m_whitelistedFunctions.add("optimize");
122 
123     // SQLite ICU functions
124     // like(), lower() and upper() are already in the list
125     m_whitelistedFunctions.add("regexp");
126 }
127 
createTable(const String & tableName)128 int DatabaseAuthorizer::createTable(const String& tableName)
129 {
130     if (!allowWrite())
131         return SQLAuthDeny;
132 
133     m_lastActionChangedDatabase = true;
134     return denyBasedOnTableName(tableName);
135 }
136 
createTempTable(const String & tableName)137 int DatabaseAuthorizer::createTempTable(const String& tableName)
138 {
139     // SQLITE_CREATE_TEMP_TABLE results in a UPDATE operation, which is not
140     // allowed in read-only transactions or private browsing, so we might as
141     // well disallow SQLITE_CREATE_TEMP_TABLE in these cases
142     if (!allowWrite())
143         return SQLAuthDeny;
144 
145     return denyBasedOnTableName(tableName);
146 }
147 
dropTable(const String & tableName)148 int DatabaseAuthorizer::dropTable(const String& tableName)
149 {
150     if (!allowWrite())
151         return SQLAuthDeny;
152 
153     return updateDeletesBasedOnTableName(tableName);
154 }
155 
dropTempTable(const String & tableName)156 int DatabaseAuthorizer::dropTempTable(const String& tableName)
157 {
158     // SQLITE_DROP_TEMP_TABLE results in a DELETE operation, which is not
159     // allowed in read-only transactions or private browsing, so we might as
160     // well disallow SQLITE_DROP_TEMP_TABLE in these cases
161     if (!allowWrite())
162         return SQLAuthDeny;
163 
164     return updateDeletesBasedOnTableName(tableName);
165 }
166 
allowAlterTable(const String &,const String & tableName)167 int DatabaseAuthorizer::allowAlterTable(const String&, const String& tableName)
168 {
169     if (!allowWrite())
170         return SQLAuthDeny;
171 
172     m_lastActionChangedDatabase = true;
173     return denyBasedOnTableName(tableName);
174 }
175 
createIndex(const String &,const String & tableName)176 int DatabaseAuthorizer::createIndex(const String&, const String& tableName)
177 {
178     if (!allowWrite())
179         return SQLAuthDeny;
180 
181     m_lastActionChangedDatabase = true;
182     return denyBasedOnTableName(tableName);
183 }
184 
createTempIndex(const String &,const String & tableName)185 int DatabaseAuthorizer::createTempIndex(const String&, const String& tableName)
186 {
187     // SQLITE_CREATE_TEMP_INDEX should result in a UPDATE or INSERT operation,
188     // which is not allowed in read-only transactions or private browsing,
189     // so we might as well disallow SQLITE_CREATE_TEMP_INDEX in these cases
190     if (!allowWrite())
191         return SQLAuthDeny;
192 
193     return denyBasedOnTableName(tableName);
194 }
195 
dropIndex(const String &,const String & tableName)196 int DatabaseAuthorizer::dropIndex(const String&, const String& tableName)
197 {
198     if (!allowWrite())
199         return SQLAuthDeny;
200 
201     return updateDeletesBasedOnTableName(tableName);
202 }
203 
dropTempIndex(const String &,const String & tableName)204 int DatabaseAuthorizer::dropTempIndex(const String&, const String& tableName)
205 {
206     // SQLITE_DROP_TEMP_INDEX should result in a DELETE operation, which is
207     // not allowed in read-only transactions or private browsing, so we might
208     // as well disallow SQLITE_DROP_TEMP_INDEX in these cases
209     if (!allowWrite())
210         return SQLAuthDeny;
211 
212     return updateDeletesBasedOnTableName(tableName);
213 }
214 
createTrigger(const String &,const String & tableName)215 int DatabaseAuthorizer::createTrigger(const String&, const String& tableName)
216 {
217     if (!allowWrite())
218         return SQLAuthDeny;
219 
220     m_lastActionChangedDatabase = true;
221     return denyBasedOnTableName(tableName);
222 }
223 
createTempTrigger(const String &,const String & tableName)224 int DatabaseAuthorizer::createTempTrigger(const String&, const String& tableName)
225 {
226     // SQLITE_CREATE_TEMP_TRIGGER results in a INSERT operation, which is not
227     // allowed in read-only transactions or private browsing, so we might as
228     // well disallow SQLITE_CREATE_TEMP_TRIGGER in these cases
229     if (!allowWrite())
230         return SQLAuthDeny;
231 
232     return denyBasedOnTableName(tableName);
233 }
234 
dropTrigger(const String &,const String & tableName)235 int DatabaseAuthorizer::dropTrigger(const String&, const String& tableName)
236 {
237     if (!allowWrite())
238         return SQLAuthDeny;
239 
240     return updateDeletesBasedOnTableName(tableName);
241 }
242 
dropTempTrigger(const String &,const String & tableName)243 int DatabaseAuthorizer::dropTempTrigger(const String&, const String& tableName)
244 {
245     // SQLITE_DROP_TEMP_TRIGGER results in a DELETE operation, which is not
246     // allowed in read-only transactions or private browsing, so we might as
247     // well disallow SQLITE_DROP_TEMP_TRIGGER in these cases
248     if (!allowWrite())
249         return SQLAuthDeny;
250 
251     return updateDeletesBasedOnTableName(tableName);
252 }
253 
createView(const String &)254 int DatabaseAuthorizer::createView(const String&)
255 {
256     return (!allowWrite() ? SQLAuthDeny : SQLAuthAllow);
257 }
258 
createTempView(const String &)259 int DatabaseAuthorizer::createTempView(const String&)
260 {
261     // SQLITE_CREATE_TEMP_VIEW results in a UPDATE operation, which is not
262     // allowed in read-only transactions or private browsing, so we might as
263     // well disallow SQLITE_CREATE_TEMP_VIEW in these cases
264     return (!allowWrite() ? SQLAuthDeny : SQLAuthAllow);
265 }
266 
dropView(const String &)267 int DatabaseAuthorizer::dropView(const String&)
268 {
269     if (!allowWrite())
270         return SQLAuthDeny;
271 
272     m_hadDeletes = true;
273     return SQLAuthAllow;
274 }
275 
dropTempView(const String &)276 int DatabaseAuthorizer::dropTempView(const String&)
277 {
278     // SQLITE_DROP_TEMP_VIEW results in a DELETE operation, which is not
279     // allowed in read-only transactions or private browsing, so we might as
280     // well disallow SQLITE_DROP_TEMP_VIEW in these cases
281     if (!allowWrite())
282         return SQLAuthDeny;
283 
284     m_hadDeletes = true;
285     return SQLAuthAllow;
286 }
287 
createVTable(const String & tableName,const String & moduleName)288 int DatabaseAuthorizer::createVTable(const String& tableName, const String& moduleName)
289 {
290     if (!allowWrite())
291         return SQLAuthDeny;
292 
293     // Allow only the FTS3 extension
294     if (!equalIgnoringCase(moduleName, "fts3"))
295         return SQLAuthDeny;
296 
297     m_lastActionChangedDatabase = true;
298     return denyBasedOnTableName(tableName);
299 }
300 
dropVTable(const String & tableName,const String & moduleName)301 int DatabaseAuthorizer::dropVTable(const String& tableName, const String& moduleName)
302 {
303     if (!allowWrite())
304         return SQLAuthDeny;
305 
306     // Allow only the FTS3 extension
307     if (!equalIgnoringCase(moduleName, "fts3"))
308         return SQLAuthDeny;
309 
310     return updateDeletesBasedOnTableName(tableName);
311 }
312 
allowDelete(const String & tableName)313 int DatabaseAuthorizer::allowDelete(const String& tableName)
314 {
315     if (!allowWrite())
316         return SQLAuthDeny;
317 
318     return updateDeletesBasedOnTableName(tableName);
319 }
320 
allowInsert(const String & tableName)321 int DatabaseAuthorizer::allowInsert(const String& tableName)
322 {
323     if (!allowWrite())
324         return SQLAuthDeny;
325 
326     m_lastActionChangedDatabase = true;
327     m_lastActionWasInsert = true;
328     return denyBasedOnTableName(tableName);
329 }
330 
allowUpdate(const String & tableName,const String &)331 int DatabaseAuthorizer::allowUpdate(const String& tableName, const String&)
332 {
333     if (!allowWrite())
334         return SQLAuthDeny;
335 
336     m_lastActionChangedDatabase = true;
337     return denyBasedOnTableName(tableName);
338 }
339 
allowTransaction()340 int DatabaseAuthorizer::allowTransaction()
341 {
342     return m_securityEnabled ? SQLAuthDeny : SQLAuthAllow;
343 }
344 
allowRead(const String & tableName,const String &)345 int DatabaseAuthorizer::allowRead(const String& tableName, const String&)
346 {
347     if (m_permissions & NoAccessMask && m_securityEnabled)
348         return SQLAuthDeny;
349 
350     return denyBasedOnTableName(tableName);
351 }
352 
allowReindex(const String &)353 int DatabaseAuthorizer::allowReindex(const String&)
354 {
355     return (!allowWrite() ? SQLAuthDeny : SQLAuthAllow);
356 }
357 
allowAnalyze(const String & tableName)358 int DatabaseAuthorizer::allowAnalyze(const String& tableName)
359 {
360     return denyBasedOnTableName(tableName);
361 }
362 
allowPragma(const String &,const String &)363 int DatabaseAuthorizer::allowPragma(const String&, const String&)
364 {
365     return m_securityEnabled ? SQLAuthDeny : SQLAuthAllow;
366 }
367 
allowAttach(const String &)368 int DatabaseAuthorizer::allowAttach(const String&)
369 {
370     return m_securityEnabled ? SQLAuthDeny : SQLAuthAllow;
371 }
372 
allowDetach(const String &)373 int DatabaseAuthorizer::allowDetach(const String&)
374 {
375     return m_securityEnabled ? SQLAuthDeny : SQLAuthAllow;
376 }
377 
allowFunction(const String & functionName)378 int DatabaseAuthorizer::allowFunction(const String& functionName)
379 {
380     if (m_securityEnabled && !m_whitelistedFunctions.contains(functionName))
381         return SQLAuthDeny;
382 
383     return SQLAuthAllow;
384 }
385 
disable()386 void DatabaseAuthorizer::disable()
387 {
388     m_securityEnabled = false;
389 }
390 
enable()391 void DatabaseAuthorizer::enable()
392 {
393     m_securityEnabled = true;
394 }
395 
allowWrite()396 bool DatabaseAuthorizer::allowWrite()
397 {
398     return !(m_securityEnabled && (m_permissions & ReadOnlyMask || m_permissions & NoAccessMask));
399 }
400 
setReadOnly()401 void DatabaseAuthorizer::setReadOnly()
402 {
403     m_permissions |= ReadOnlyMask;
404 }
405 
setPermissions(int permissions)406 void DatabaseAuthorizer::setPermissions(int permissions)
407 {
408     m_permissions = permissions;
409 }
410 
denyBasedOnTableName(const String & tableName) const411 int DatabaseAuthorizer::denyBasedOnTableName(const String& tableName) const
412 {
413     if (!m_securityEnabled)
414         return SQLAuthAllow;
415 
416     // Sadly, normal creates and drops end up affecting sqlite_master in an authorizer callback, so
417     // it will be tough to enforce all of the following policies
418     //if (equalIgnoringCase(tableName, "sqlite_master") || equalIgnoringCase(tableName, "sqlite_temp_master") ||
419     //    equalIgnoringCase(tableName, "sqlite_sequence") || equalIgnoringCase(tableName, Database::databaseInfoTableName()))
420     //        return SQLAuthDeny;
421 
422     if (equalIgnoringCase(tableName, m_databaseInfoTableName))
423         return SQLAuthDeny;
424 
425     return SQLAuthAllow;
426 }
427 
updateDeletesBasedOnTableName(const String & tableName)428 int DatabaseAuthorizer::updateDeletesBasedOnTableName(const String& tableName)
429 {
430     int allow = denyBasedOnTableName(tableName);
431     if (allow)
432         m_hadDeletes = true;
433     return allow;
434 }
435 
436 } // namespace WebCore
437 
438 #endif
439