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