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 37namespace WebCore { 38 39PassRefPtr<DatabaseAuthorizer> DatabaseAuthorizer::create(const String& databaseInfoTableName) 40{ 41 return adoptRef(new DatabaseAuthorizer(databaseInfoTableName)); 42} 43 44DatabaseAuthorizer::DatabaseAuthorizer(const String& databaseInfoTableName) 45 : m_securityEnabled(false) 46 , m_databaseInfoTableName(databaseInfoTableName) 47{ 48 reset(); 49 addWhitelistedFunctions(); 50} 51 52void DatabaseAuthorizer::reset() 53{ 54 m_lastActionWasInsert = false; 55 m_lastActionChangedDatabase = false; 56 m_permissions = ReadWriteMask; 57} 58 59void DatabaseAuthorizer::resetDeletes() 60{ 61 m_hadDeletes = false; 62} 63 64void 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 128int DatabaseAuthorizer::createTable(const String& tableName) 129{ 130 if (!allowWrite()) 131 return SQLAuthDeny; 132 133 m_lastActionChangedDatabase = true; 134 return denyBasedOnTableName(tableName); 135} 136 137int 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 148int DatabaseAuthorizer::dropTable(const String& tableName) 149{ 150 if (!allowWrite()) 151 return SQLAuthDeny; 152 153 return updateDeletesBasedOnTableName(tableName); 154} 155 156int 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 167int 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 176int 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 185int 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 196int DatabaseAuthorizer::dropIndex(const String&, const String& tableName) 197{ 198 if (!allowWrite()) 199 return SQLAuthDeny; 200 201 return updateDeletesBasedOnTableName(tableName); 202} 203 204int 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 215int 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 224int 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 235int DatabaseAuthorizer::dropTrigger(const String&, const String& tableName) 236{ 237 if (!allowWrite()) 238 return SQLAuthDeny; 239 240 return updateDeletesBasedOnTableName(tableName); 241} 242 243int 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 254int DatabaseAuthorizer::createView(const String&) 255{ 256 return (!allowWrite() ? SQLAuthDeny : SQLAuthAllow); 257} 258 259int 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 267int DatabaseAuthorizer::dropView(const String&) 268{ 269 if (!allowWrite()) 270 return SQLAuthDeny; 271 272 m_hadDeletes = true; 273 return SQLAuthAllow; 274} 275 276int 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 288int 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 301int 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 313int DatabaseAuthorizer::allowDelete(const String& tableName) 314{ 315 if (!allowWrite()) 316 return SQLAuthDeny; 317 318 return updateDeletesBasedOnTableName(tableName); 319} 320 321int 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 331int 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 340int DatabaseAuthorizer::allowTransaction() 341{ 342 return m_securityEnabled ? SQLAuthDeny : SQLAuthAllow; 343} 344 345int 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 353int DatabaseAuthorizer::allowReindex(const String&) 354{ 355 return (!allowWrite() ? SQLAuthDeny : SQLAuthAllow); 356} 357 358int DatabaseAuthorizer::allowAnalyze(const String& tableName) 359{ 360 return denyBasedOnTableName(tableName); 361} 362 363int DatabaseAuthorizer::allowPragma(const String&, const String&) 364{ 365 return m_securityEnabled ? SQLAuthDeny : SQLAuthAllow; 366} 367 368int DatabaseAuthorizer::allowAttach(const String&) 369{ 370 return m_securityEnabled ? SQLAuthDeny : SQLAuthAllow; 371} 372 373int DatabaseAuthorizer::allowDetach(const String&) 374{ 375 return m_securityEnabled ? SQLAuthDeny : SQLAuthAllow; 376} 377 378int DatabaseAuthorizer::allowFunction(const String& functionName) 379{ 380 if (m_securityEnabled && !m_whitelistedFunctions.contains(functionName)) 381 return SQLAuthDeny; 382 383 return SQLAuthAllow; 384} 385 386void DatabaseAuthorizer::disable() 387{ 388 m_securityEnabled = false; 389} 390 391void DatabaseAuthorizer::enable() 392{ 393 m_securityEnabled = true; 394} 395 396bool DatabaseAuthorizer::allowWrite() 397{ 398 return !(m_securityEnabled && (m_permissions & ReadOnlyMask || m_permissions & NoAccessMask)); 399} 400 401void DatabaseAuthorizer::setReadOnly() 402{ 403 m_permissions |= ReadOnlyMask; 404} 405 406void DatabaseAuthorizer::setPermissions(int permissions) 407{ 408 m_permissions = permissions; 409} 410 411int 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 428int 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