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