Experimental branch with new sqlite3_db_config() options that could possible
enhance security for applications reading potentially compromised database
files.

FossilOrigin-Name: 96a2db2612f2e47bbec0e374a242820c88f03c42ccbf8467abccaef41469bae2
diff --git a/src/main.c b/src/main.c
index 1afeee0..70c5b89 100644
--- a/src/main.c
+++ b/src/main.c
@@ -852,6 +852,8 @@
         { SQLITE_DBCONFIG_DQS_DDL,               SQLITE_DqsDDL         },
         { SQLITE_DBCONFIG_DQS_DML,               SQLITE_DqsDML         },
         { SQLITE_DBCONFIG_LEGACY_FILE_FORMAT,    SQLITE_LegacyFileFmt  },
+        { SQLITE_DBCONFIG_UNSAFE_FUNC_IN_VIEW,   SQLITE_UnsafeInView   },
+        { SQLITE_DBCONFIG_VTAB_IN_VIEW,          SQLITE_VtabInView     },
       };
       unsigned int i;
       rc = SQLITE_ERROR; /* IMP: R-42790-23372 */
@@ -3082,6 +3084,8 @@
                  | SQLITE_EnableTrigger
                  | SQLITE_EnableView
                  | SQLITE_CacheSpill
+                 | SQLITE_UnsafeInView
+                 | SQLITE_VtabInView
 
 /* The SQLITE_DQS compile-time option determines the default settings
 ** for SQLITE_DBCONFIG_DQS_DDL and SQLITE_DBCONFIG_DQS_DML.
diff --git a/src/resolve.c b/src/resolve.c
index a0f9c0f..36eef4b 100644
--- a/src/resolve.c
+++ b/src/resolve.c
@@ -861,6 +861,16 @@
           ** constant because they are constant for the duration of one query.
           ** This allows them to be factored out of inner loops. */
           ExprSetProperty(pExpr,EP_ConstFunc);
+        }else{
+          if( ExprHasProperty(pExpr, EP_Indirect)
+           && !IN_RENAME_OBJECT
+           && (pParse->db->flags & SQLITE_UnsafeInView)==0
+          ){
+            /* If SQLITE_DBCONFIG_UNSAFE_IN_VIEW is off, then functions with
+            ** side effects are not allowed inside triggers and views. */
+            sqlite3ErrorMsg(pParse, "%s() prohibited in triggers and views",
+                            pDef->zName);
+          }
         }
         if( (pDef->funcFlags & SQLITE_FUNC_CONSTANT)==0 ){
           /* Date/time functions that use 'now', and other functions like
diff --git a/src/shell.c.in b/src/shell.c.in
index e6b6f1a..1a06bf8 100644
--- a/src/shell.c.in
+++ b/src/shell.c.in
@@ -7159,21 +7159,23 @@
       const char *zName;
       int op;
     } aDbConfig[] = {
+        { "defensive",          SQLITE_DBCONFIG_DEFENSIVE             },
+        { "dqs_ddl",            SQLITE_DBCONFIG_DQS_DDL               },
+        { "dqs_dml",            SQLITE_DBCONFIG_DQS_DML               },
         { "enable_fkey",        SQLITE_DBCONFIG_ENABLE_FKEY           },
+        { "enable_qpsg",        SQLITE_DBCONFIG_ENABLE_QPSG           },
         { "enable_trigger",     SQLITE_DBCONFIG_ENABLE_TRIGGER        },
         { "enable_view",        SQLITE_DBCONFIG_ENABLE_VIEW           },
         { "fts3_tokenizer",     SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER },
+        { "legacy_alter_table", SQLITE_DBCONFIG_LEGACY_ALTER_TABLE    },
+        { "legacy_file_format", SQLITE_DBCONFIG_LEGACY_FILE_FORMAT    },
         { "load_extension",     SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION },
         { "no_ckpt_on_close",   SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE      },
-        { "enable_qpsg",        SQLITE_DBCONFIG_ENABLE_QPSG           },
-        { "trigger_eqp",        SQLITE_DBCONFIG_TRIGGER_EQP           },
         { "reset_database",     SQLITE_DBCONFIG_RESET_DATABASE        },
-        { "defensive",          SQLITE_DBCONFIG_DEFENSIVE             },
+        { "trigger_eqp",        SQLITE_DBCONFIG_TRIGGER_EQP           },
+        { "unsafe_func_in_view",SQLITE_DBCONFIG_UNSAFE_FUNC_IN_VIEW   },
+        { "vtab_in_view",       SQLITE_DBCONFIG_VTAB_IN_VIEW          },
         { "writable_schema",    SQLITE_DBCONFIG_WRITABLE_SCHEMA       },
-        { "legacy_alter_table", SQLITE_DBCONFIG_LEGACY_ALTER_TABLE    },
-        { "dqs_dml",            SQLITE_DBCONFIG_DQS_DML               },
-        { "dqs_ddl",            SQLITE_DBCONFIG_DQS_DDL               },
-        { "legacy_file_format", SQLITE_DBCONFIG_LEGACY_FILE_FORMAT    },
     };
     int ii, v;
     open_db(p, 0);
@@ -7183,7 +7185,7 @@
         sqlite3_db_config(p->db, aDbConfig[ii].op, booleanValue(azArg[2]), 0);
       }
       sqlite3_db_config(p->db, aDbConfig[ii].op, -1, &v);
-      utf8_printf(p->out, "%18s %s\n", aDbConfig[ii].zName, v ? "on" : "off");
+      utf8_printf(p->out, "%19s %s\n", aDbConfig[ii].zName, v ? "on" : "off");
       if( nArg>1 ) break;
     }
     if( nArg>1 && ii==ArraySize(aDbConfig) ){
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index 50976ee..03e92a4 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -2265,6 +2265,33 @@
 ** compile-time option.
 ** </dd>
 **
+** [[SQLITE_DBCONFIG_UNSAFE_FUNC_IN_VIEW]]
+** <dt>SQLITE_DBCONFIG_UNSAFE_FUNC_IN_VIEW</td>
+** <dd>The SQLITE_DBCONFIG_UNSAFE_FUNC_IN_VIEW option activates or deactivates
+** the ability to use SQL functions that have side-effects inside of
+** triggers and views.  For legacy compatibility, this setting defaults
+** to "on".  Applications that are operating on untrusted database files
+** are advised to change this setting to "off".  When this setting is on,
+** only functions that have no side effects are usable inside of views.
+** This prevents an attacker from modifying the schema of a database so
+** that views and/or triggers with undesirable side-effects are run when
+** the application innocently tries to access what it thinks is an ordinary
+** table.
+** </dd>
+**
+** [[SQLITE_DBCONFIG_VTAB_IN_VIEW]]
+** <dt>SQLITE_DBCONFIG_VTAB_IN_VIEW</td>
+** <dd>The SQLITE_DBCONFIG_VTAB_IN_VIEW option activates or deactivates
+** the ability to use [virtual tables] inside of triggers and views.
+** For legacy compatibility, this setting defaults
+** to "on".  Applications that are operating on untrusted database files
+** are advised to change this setting to "off".  Turning this setting off
+** prevents an attacker from modifying the schema of a database so
+** that views and/or triggers with undesirable side-effects are run when
+** the application innocently tries to access what it thinks is an ordinary
+** table.
+** </dd>
+**
 ** [[SQLITE_DBCONFIG_LEGACY_FILE_FORMAT]]
 ** <dt>SQLITE_DBCONFIG_LEGACY_FILE_FORMAT</td>
 ** <dd>The SQLITE_DBCONFIG_LEGACY_FILE_FORMAT option activates or deactivates
@@ -2305,7 +2332,9 @@
 #define SQLITE_DBCONFIG_DQS_DDL               1014 /* int int* */
 #define SQLITE_DBCONFIG_ENABLE_VIEW           1015 /* int int* */
 #define SQLITE_DBCONFIG_LEGACY_FILE_FORMAT    1016 /* int int* */
-#define SQLITE_DBCONFIG_MAX                   1016 /* Largest DBCONFIG */
+#define SQLITE_DBCONFIG_UNSAFE_FUNC_IN_VIEW   1017 /* int int* */
+#define SQLITE_DBCONFIG_VTAB_IN_VIEW          1018 /* int int* */
+#define SQLITE_DBCONFIG_MAX                   1018 /* Largest DBCONFIG */
 
 /*
 ** CAPI3REF: Enable Or Disable Extended Result Codes
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 0dcb103..d0452f5 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -1142,6 +1142,7 @@
 ** A bit in a Bitmask
 */
 #define MASKBIT(n)   (((Bitmask)1)<<(n))
+#define MASKBIT64(n) (((u64)1)<<(n))
 #define MASKBIT32(n) (((unsigned int)1)<<(n))
 #define ALLBITS      ((Bitmask)-1)
 
@@ -1527,6 +1528,13 @@
 #define ENC(db)        ((db)->enc)
 
 /*
+** A u64 constant where the lower 32 bits are all zeros.  Only the
+** upper 32 bits are included in the argument.  Necessary because some
+** C-compilers still do not accept LL integer literals.
+*/
+#define HI(X)  ((u64)(X)<<32)
+
+/*
 ** Possible values for the sqlite3.flags.
 **
 ** Value constraints (enforced via assert()):
@@ -1541,11 +1549,10 @@
 #define SQLITE_CkptFullFSync  0x00000010  /* Use full fsync for checkpoint */
 #define SQLITE_CacheSpill     0x00000020  /* OK to spill pager cache */
 #define SQLITE_ShortColNames  0x00000040  /* Show short columns names */
-#define SQLITE_CountRows      0x00000080  /* Count rows changed by INSERT, */
-                                          /*   DELETE, or UPDATE and return */
-                                          /*   the count using a callback. */
-#define SQLITE_NullCallback   0x00000100  /* Invoke the callback once if the */
-                                          /*   result set is empty */
+#define SQLITE_UnsafeInView   0x00000080  /* Allow functions with side-effect
+                                          ** in triggers and views */
+#define SQLITE_VtabInView     0x00000100  /* Allow views and triggers to access
+                                          ** virtual tables */
 #define SQLITE_IgnoreChecks   0x00000200  /* Do not enforce check constraints */
 #define SQLITE_ReadUncommit   0x00000400  /* READ UNCOMMITTED in shared-cache */
 #define SQLITE_NoCkptOnClose  0x00000800  /* No checkpoint on close()/DETACH */
@@ -1569,9 +1576,13 @@
 #define SQLITE_DqsDDL         0x20000000  /* dbl-quoted strings allowed in DDL*/
 #define SQLITE_DqsDML         0x40000000  /* dbl-quoted strings allowed in DML*/
 #define SQLITE_EnableView     0x80000000  /* Enable the use of views */
+#define SQLITE_CountRows      HI(0x00001) /* Count rows changed by INSERT, */
+                                          /*   DELETE, or UPDATE and return */
+                                          /*   the count using a callback. */
+#define SQLITE_NullCallback   HI(0000002) /* Invoke the callback once if the */
+                                          /*   result set is empty */
 
 /* Flags used only if debugging */
-#define HI(X)  ((u64)(X)<<32)
 #ifdef SQLITE_DEBUG
 #define SQLITE_SqlTrace       HI(0x0100000) /* Debug print SQL as it executes */
 #define SQLITE_VdbeListing    HI(0x0200000) /* Debug listings of VDBE progs */