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