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