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