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 <wtf/PassRefPtr.h> 33#include <wtf/text/WTFString.h> 34 35namespace WebCore { 36 37PassRefPtr<DatabaseAuthorizer> DatabaseAuthorizer::create(const String& databaseInfoTableName) 38{ 39 return adoptRef(new DatabaseAuthorizer(databaseInfoTableName)); 40} 41 42DatabaseAuthorizer::DatabaseAuthorizer(const String& databaseInfoTableName) 43 : m_securityEnabled(false) 44 , m_databaseInfoTableName(databaseInfoTableName) 45{ 46 reset(); 47 addWhitelistedFunctions(); 48} 49 50void DatabaseAuthorizer::reset() 51{ 52 m_lastActionWasInsert = false; 53 m_lastActionChangedDatabase = false; 54 m_permissions = ReadWriteMask; 55} 56 57void DatabaseAuthorizer::resetDeletes() 58{ 59 m_hadDeletes = false; 60} 61 62void 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 126int DatabaseAuthorizer::createTable(const String& tableName) 127{ 128 if (!allowWrite()) 129 return SQLAuthDeny; 130 131 m_lastActionChangedDatabase = true; 132 return denyBasedOnTableName(tableName); 133} 134 135int 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 146int DatabaseAuthorizer::dropTable(const String& tableName) 147{ 148 if (!allowWrite()) 149 return SQLAuthDeny; 150 151 return updateDeletesBasedOnTableName(tableName); 152} 153 154int 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 165int 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 174int 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 183int 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 194int DatabaseAuthorizer::dropIndex(const String&, const String& tableName) 195{ 196 if (!allowWrite()) 197 return SQLAuthDeny; 198 199 return updateDeletesBasedOnTableName(tableName); 200} 201 202int 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 213int 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 222int 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 233int DatabaseAuthorizer::dropTrigger(const String&, const String& tableName) 234{ 235 if (!allowWrite()) 236 return SQLAuthDeny; 237 238 return updateDeletesBasedOnTableName(tableName); 239} 240 241int 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 252int DatabaseAuthorizer::createView(const String&) 253{ 254 return (!allowWrite() ? SQLAuthDeny : SQLAuthAllow); 255} 256 257int 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 265int DatabaseAuthorizer::dropView(const String&) 266{ 267 if (!allowWrite()) 268 return SQLAuthDeny; 269 270 m_hadDeletes = true; 271 return SQLAuthAllow; 272} 273 274int 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 286int 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 299int 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 311int DatabaseAuthorizer::allowDelete(const String& tableName) 312{ 313 if (!allowWrite()) 314 return SQLAuthDeny; 315 316 return updateDeletesBasedOnTableName(tableName); 317} 318 319int 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 329int 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 338int DatabaseAuthorizer::allowTransaction() 339{ 340 return m_securityEnabled ? SQLAuthDeny : SQLAuthAllow; 341} 342 343int 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 351int DatabaseAuthorizer::allowReindex(const String&) 352{ 353 return (!allowWrite() ? SQLAuthDeny : SQLAuthAllow); 354} 355 356int DatabaseAuthorizer::allowAnalyze(const String& tableName) 357{ 358 return denyBasedOnTableName(tableName); 359} 360 361int DatabaseAuthorizer::allowPragma(const String&, const String&) 362{ 363 return m_securityEnabled ? SQLAuthDeny : SQLAuthAllow; 364} 365 366int DatabaseAuthorizer::allowAttach(const String&) 367{ 368 return m_securityEnabled ? SQLAuthDeny : SQLAuthAllow; 369} 370 371int DatabaseAuthorizer::allowDetach(const String&) 372{ 373 return m_securityEnabled ? SQLAuthDeny : SQLAuthAllow; 374} 375 376int DatabaseAuthorizer::allowFunction(const String& functionName) 377{ 378 if (m_securityEnabled && !m_whitelistedFunctions.contains(functionName)) 379 return SQLAuthDeny; 380 381 return SQLAuthAllow; 382} 383 384void DatabaseAuthorizer::disable() 385{ 386 m_securityEnabled = false; 387} 388 389void DatabaseAuthorizer::enable() 390{ 391 m_securityEnabled = true; 392} 393 394bool DatabaseAuthorizer::allowWrite() 395{ 396 return !(m_securityEnabled && (m_permissions & ReadOnlyMask || m_permissions & NoAccessMask)); 397} 398 399void DatabaseAuthorizer::setReadOnly() 400{ 401 m_permissions |= ReadOnlyMask; 402} 403 404void DatabaseAuthorizer::setPermissions(int permissions) 405{ 406 m_permissions = permissions; 407} 408 409int 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 426int 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 435