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