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 34namespace blink { 35 36PassRefPtrWillBeRawPtr<DatabaseAuthorizer> DatabaseAuthorizer::create(const String& databaseInfoTableName) 37{ 38 return adoptRefWillBeNoop(new DatabaseAuthorizer(databaseInfoTableName)); 39} 40 41DatabaseAuthorizer::DatabaseAuthorizer(const String& databaseInfoTableName) 42 : m_securityEnabled(false) 43 , m_databaseInfoTableName(databaseInfoTableName) 44{ 45 reset(); 46 addWhitelistedFunctions(); 47} 48 49void DatabaseAuthorizer::reset() 50{ 51 m_lastActionWasInsert = false; 52 m_lastActionChangedDatabase = false; 53 m_permissions = ReadWriteMask; 54} 55 56void DatabaseAuthorizer::resetDeletes() 57{ 58 m_hadDeletes = false; 59} 60 61void 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 125int DatabaseAuthorizer::createTable(const String& tableName) 126{ 127 if (!allowWrite()) 128 return SQLAuthDeny; 129 130 m_lastActionChangedDatabase = true; 131 return denyBasedOnTableName(tableName); 132} 133 134int 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 145int DatabaseAuthorizer::dropTable(const String& tableName) 146{ 147 if (!allowWrite()) 148 return SQLAuthDeny; 149 150 return updateDeletesBasedOnTableName(tableName); 151} 152 153int 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 164int 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 173int 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 182int 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 193int DatabaseAuthorizer::dropIndex(const String&, const String& tableName) 194{ 195 if (!allowWrite()) 196 return SQLAuthDeny; 197 198 return updateDeletesBasedOnTableName(tableName); 199} 200 201int 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 212int 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 221int 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 232int DatabaseAuthorizer::dropTrigger(const String&, const String& tableName) 233{ 234 if (!allowWrite()) 235 return SQLAuthDeny; 236 237 return updateDeletesBasedOnTableName(tableName); 238} 239 240int 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 251int DatabaseAuthorizer::createView(const String&) 252{ 253 return (!allowWrite() ? SQLAuthDeny : SQLAuthAllow); 254} 255 256int 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 264int DatabaseAuthorizer::dropView(const String&) 265{ 266 if (!allowWrite()) 267 return SQLAuthDeny; 268 269 m_hadDeletes = true; 270 return SQLAuthAllow; 271} 272 273int 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 285int 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 298int 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 310int DatabaseAuthorizer::allowDelete(const String& tableName) 311{ 312 if (!allowWrite()) 313 return SQLAuthDeny; 314 315 return updateDeletesBasedOnTableName(tableName); 316} 317 318int 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 328int 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 337int DatabaseAuthorizer::allowTransaction() 338{ 339 return m_securityEnabled ? SQLAuthDeny : SQLAuthAllow; 340} 341 342int 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 350int DatabaseAuthorizer::allowReindex(const String&) 351{ 352 return (!allowWrite() ? SQLAuthDeny : SQLAuthAllow); 353} 354 355int DatabaseAuthorizer::allowAnalyze(const String& tableName) 356{ 357 return denyBasedOnTableName(tableName); 358} 359 360int DatabaseAuthorizer::allowPragma(const String&, const String&) 361{ 362 return m_securityEnabled ? SQLAuthDeny : SQLAuthAllow; 363} 364 365int DatabaseAuthorizer::allowAttach(const String&) 366{ 367 return m_securityEnabled ? SQLAuthDeny : SQLAuthAllow; 368} 369 370int DatabaseAuthorizer::allowDetach(const String&) 371{ 372 return m_securityEnabled ? SQLAuthDeny : SQLAuthAllow; 373} 374 375int DatabaseAuthorizer::allowFunction(const String& functionName) 376{ 377 if (m_securityEnabled && !m_whitelistedFunctions.contains(functionName)) 378 return SQLAuthDeny; 379 380 return SQLAuthAllow; 381} 382 383void DatabaseAuthorizer::disable() 384{ 385 m_securityEnabled = false; 386} 387 388void DatabaseAuthorizer::enable() 389{ 390 m_securityEnabled = true; 391} 392 393bool DatabaseAuthorizer::allowWrite() 394{ 395 return !(m_securityEnabled && (m_permissions & ReadOnlyMask || m_permissions & NoAccessMask)); 396} 397 398void DatabaseAuthorizer::setPermissions(int permissions) 399{ 400 m_permissions = permissions; 401} 402 403int 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 420int 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