]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add the --safe to the CLI. Also the --nonce option and the .nonce command.
authordrh <>
Thu, 26 Aug 2021 18:31:39 +0000 (18:31 +0000)
committerdrh <>
Thu, 26 Aug 2021 18:31:39 +0000 (18:31 +0000)
FossilOrigin-Name: c76870cb1a8e2e1389ad864c51b9f596dff21df8bb58f438f0a2cacfa63b22a4

manifest
manifest.uuid
src/shell.c.in

index e206e9ae54748fc96417411beb0904b7a7c095e0..7e071f28fb8a00c34fd26cc4c204d1c5e95b9932 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Correctly\spreserve\sthe\scollating\ssequence\sfor\sa\scolumn\swhen\schanging\nits\sdatatype.\s\sFix\sfor\sthe\sproblem\sreported\sby\n[forum:/forumpost/e5c76b738e|forum\spost\se5c76b738e].\s\sTest\scases\nin\sTH3.
-D 2021-08-24T17:07:44.447
+C Add\sthe\s--safe\sto\sthe\sCLI.\s\sAlso\sthe\s--nonce\soption\sand\sthe\s.nonce\scommand.
+D 2021-08-26T18:31:39.329
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -545,7 +545,7 @@ F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c
 F src/resolve.c 42b94d37a54200707a95566eff4f7e8a380e32d080016b699f23bd79a73a5028
 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
 F src/select.c b2c48dfc02b486fd2da2be1605503615958ba1997d40d994c2946975d0150a31
-F src/shell.c.in f795a4ae3c35631f5edcfa754c7824ff1d8a75b23a07e22e664b50f82e826346
+F src/shell.c.in 34cc533f27d522c7c93fe38c99867c460b0b08be9c1c315dbd360ba5d865b19f
 F src/sqlite.h.in 4e977a5e2ed1a9e8987ff65a2cab5f99a4298ebf040ea5ff636e1753339ff45a
 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
 F src/sqlite3ext.h e97f4e9b509408fea4c4e9bef5a41608dfac343b4d3c7a990dedde1e19af9510
@@ -1922,7 +1922,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P d953646a63bf96a8e6e57fefaa60ae1487e5e4eb776fb38cd9c4ce002e74d016
-R d53f561ead2efd21aac670378e59272f
+P c7f0813cabf9d8ab367bead5ba8cf20132b8bb9274d8e47b76ad66a10517dd2a
+R 96ba0fa0400f19ae37fbb446bcbce223
 U drh
-Z c6e1ab5b9f0457c342ae407c84026d23
+Z c0d94ba9195f86107b44ea4e3e28e613
index f00b8ef6b23a0141a84fe07f086a8bc4bd33f735..bf8ee8bbc8e2e9b2fbade53678d93811edbe32dc 100644 (file)
@@ -1 +1 @@
-c7f0813cabf9d8ab367bead5ba8cf20132b8bb9274d8e47b76ad66a10517dd2a
\ No newline at end of file
+c76870cb1a8e2e1389ad864c51b9f596dff21df8bb58f438f0a2cacfa63b22a4
\ No newline at end of file
index 2ca88c02bb26e74a0231bc9c69fc0d22d8924907..10844ddeb995ff9ea6f658f30c0c74f239ecf6ce 100644 (file)
@@ -1104,6 +1104,8 @@ struct ShellState {
   u8 doXdgOpen;          /* Invoke start/open/xdg-open in output_reset() */
   u8 nEqpLevel;          /* Depth of the EQP output graph */
   u8 eTraceType;         /* SHELL_TRACE_* value for type of trace */
+  u8 bSafeMode;          /* True to prohibit unsafe operations */
+  u8 bSafeModePersist;   /* The long-term value of bSafeMode */
   unsigned statsOn;      /* True to display memory stats before each finalize */
   unsigned mEqpLines;    /* Mask of veritical lines in the EQP output graph */
   int outCount;          /* Revert to stdout when reaching zero */
@@ -1155,8 +1157,9 @@ struct ShellState {
   int *aiIndent;         /* Array of indents used in MODE_Explain */
   int nIndent;           /* Size of array aiIndent[] */
   int iIndent;           /* Index of current op in aiIndent[] */
+  char *zNonce;          /* Nonce for temporary safe-mode excapes */
   EQPGraph sGraph;       /* Information for the graphical EXPLAIN QUERY PLAN */
-  ExpertInfo expert;        /* Valid if previous command was ".expert OPT..." */
+  ExpertInfo expert;     /* Valid if previous command was ".expert OPT..." */
 };
 
 
@@ -1292,6 +1295,27 @@ static void shellPutsFunc(
   sqlite3_result_value(pCtx, apVal[0]);
 }
 
+/*
+** If in safe mode, print an error message described by the arguments
+** and exit immediately.
+*/
+static void failIfSafeMode(
+  ShellState *p,
+  const char *zErrMsg,
+  ...
+){
+  if( p->bSafeMode ){
+    va_list ap;
+    char *zMsg;
+    va_start(ap, zErrMsg);
+    zMsg = sqlite3_vmprintf(zErrMsg, ap);
+    va_end(ap);
+    raw_printf(stderr, "line %d: ", p->lineno);
+    utf8_printf(stderr, "%s\n", zMsg);
+    exit(1);
+  }
+}
+
 /*
 ** SQL function:   edit(VALUE)
 **                 edit(VALUE,EDITOR)
@@ -1769,6 +1793,49 @@ static BOOL WINAPI ConsoleCtrlHandler(
 #endif
 
 #ifndef SQLITE_OMIT_AUTHORIZATION
+/*
+** This authorizer runs in safe mode.
+*/
+static int safeModeAuth(
+  void *pClientData,
+  int op,
+  const char *zA1,
+  const char *zA2,
+  const char *zA3,
+  const char *zA4
+){
+  ShellState *p = (ShellState*)pClientData;
+  static const char *azProhibitedFunctions[] = {
+    "edit",
+    "fts3_tokenizer",
+    "load_extension",
+    "readfile",
+    "writefile",
+    "zipfile",
+    "zipfile_cds",
+  };
+  UNUSED_PARAMETER(zA2);
+  UNUSED_PARAMETER(zA3);
+  UNUSED_PARAMETER(zA4);
+  switch( op ){
+    case SQLITE_ATTACH: {
+      failIfSafeMode(p, "cannot run ATTACH in safe mode");
+      break;
+    }
+    case SQLITE_FUNCTION: {
+      int i;
+      for(i=0; i<ArraySize(azProhibitedFunctions); i++){
+        if( sqlite3_stricmp(zA1, azProhibitedFunctions[i])==0 ){
+          failIfSafeMode(p, "cannot use the %s() function in safe mode",
+                         azProhibitedFunctions[i]);
+        }
+      }
+      break;
+    }
+  }
+  return SQLITE_OK;
+}
+
 /*
 ** When the ".auth ON" is set, the following authorizer callback is
 ** invoked.  It always returns SQLITE_OK.
@@ -1811,6 +1878,7 @@ static int shellAuth(
     }
   }
   raw_printf(p->out, "\n");
+  if( p->bSafeMode ) (void)safeModeAuth(pClientData, op, zA1, zA2, zA3, zA4);
   return SQLITE_OK;
 }
 #endif
@@ -3984,6 +4052,7 @@ static const char *(azHelp[]) = {
   "     table     ASCII-art table",
   "     tabs      Tab-separated values",
   "     tcl       TCL list elements",
+  ".nonce STRING            Disable safe mode for one command if the nonce matches",
   ".nullvalue STRING        Use STRING in place of NULL values",
   ".once ?OPTIONS? ?FILE?   Output for the next SQL command only to FILE",
   "     If FILE begins with '|' then open as a pipe",
@@ -4698,6 +4767,9 @@ static void open_db(ShellState *p, int openFlags){
     }
 #endif
   }
+  if( p->bSafeModePersist && p->db!=0 ){
+    sqlite3_set_authorizer(p->db, safeModeAuth, p);
+  }
 }
 
 /*
@@ -7461,6 +7533,8 @@ static int do_meta_command(char *zLine, ShellState *p){
     open_db(p, 0);
     if( booleanValue(azArg[1]) ){
       sqlite3_set_authorizer(p->db, shellAuth, p);
+    }else if( p->bSafeModePersist ){
+      sqlite3_set_authorizer(p->db, safeModeAuth, p);
     }else{
       sqlite3_set_authorizer(p->db, 0, 0);
     }
@@ -7470,6 +7544,7 @@ static int do_meta_command(char *zLine, ShellState *p){
 #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB)
   if( c=='a' && strncmp(azArg[0], "archive", n)==0 ){
     open_db(p, 0);
+    failIfSafeMode(p, "cannot run .archive in safe mode");
     rc = arDotCommand(p, 0, azArg, nArg);
   }else
 #endif
@@ -7484,6 +7559,7 @@ static int do_meta_command(char *zLine, ShellState *p){
     int j;
     int bAsync = 0;
     const char *zVfs = 0;
+    failIfSafeMode(p, "cannot run .%s in safe mode", azArg[0]);
     for(j=1; j<nArg; j++){
       const char *z = azArg[j];
       if( z[0]=='-' ){
@@ -7572,6 +7648,7 @@ static int do_meta_command(char *zLine, ShellState *p){
   }else
 
   if( c=='c' && strcmp(azArg[0],"cd")==0 ){
+    failIfSafeMode(p, "cannot run .cd in safe mode");
     if( nArg==2 ){
 #if defined(_WIN32) || defined(WIN32)
       wchar_t *z = sqlite3_win32_utf8_to_unicode(azArg[1]);
@@ -7625,6 +7702,7 @@ static int do_meta_command(char *zLine, ShellState *p){
   }else
 
   if( c=='c' && strncmp(azArg[0], "clone", n)==0 ){
+    failIfSafeMode(p, "cannot run .clone in safe mode");
     if( nArg==2 ){
       tryToClone(p, azArg[1]);
     }else{
@@ -8186,6 +8264,7 @@ static int do_meta_command(char *zLine, ShellState *p){
     int nSkip = 0;              /* Initial lines to skip */
     int useOutputMode = 1;      /* Use output mode to determine separators */
 
+    failIfSafeMode(p, "cannot run .import in safe mode");
     memset(&sCtx, 0, sizeof(sCtx));
     if( p->mode==MODE_Ascii ){
       xRead = ascii_read_one_field;
@@ -8637,6 +8716,7 @@ static int do_meta_command(char *zLine, ShellState *p){
   if( c=='l' && strncmp(azArg[0], "load", n)==0 ){
     const char *zFile, *zProc;
     char *zErrMsg = 0;
+    failIfSafeMode(p, "cannot run .load in safe mode");
     if( nArg<2 ){
       raw_printf(stderr, "Usage: .load FILE ?ENTRYPOINT?\n");
       rc = 1;
@@ -8655,6 +8735,7 @@ static int do_meta_command(char *zLine, ShellState *p){
 #endif
 
   if( c=='l' && strncmp(azArg[0], "log", n)==0 ){
+    failIfSafeMode(p, "cannot run .log in safe mode");
     if( nArg!=2 ){
       raw_printf(stderr, "Usage: .log FILENAME\n");
       rc = 1;
@@ -8725,6 +8806,19 @@ static int do_meta_command(char *zLine, ShellState *p){
     p->cMode = p->mode;
   }else
 
+  if( c=='n' && strcmp(azArg[0], "nonce")==0 ){
+    if( nArg!=2 ){
+      raw_printf(stderr, "Usage: .nonce NONCE\n");
+      rc = 1;
+    }else if( p->zNonce==0 || strcmp(azArg[1],p->zNonce)!=0 ){
+      raw_printf(stderr, "line %d: incorrect nonce: \"%s\"\n", p->lineno, azArg[1]);
+      exit(1);
+    }
+    p->bSafeMode = 0;
+    return 0;  /* Return immediately to bypass the safe mode reset
+               ** at the end of this procedure */
+  }else
+
   if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 ){
     if( nArg==2 ){
       sqlite3_snprintf(sizeof(p->nullValue), p->nullValue,
@@ -8816,7 +8910,14 @@ static int do_meta_command(char *zLine, ShellState *p){
     }
     /* If a filename is specified, try to open it first */
     if( zNewFilename || p->openMode==SHELL_OPEN_HEXDB ){
-      if( newFlag ) shellDeleteFile(zNewFilename);
+      if( newFlag && !p->bSafeMode ) shellDeleteFile(zNewFilename);
+      if( p->bSafeMode
+       && p->openMode!=SHELL_OPEN_HEXDB
+       && zNewFilename
+       && strcmp(zNewFilename,":memory:")!=0
+      ){
+        failIfSafeMode(p, "cannot open disk-based database files in safe mode");
+      }
       p->pAuxDb->zDbFilename = zNewFilename;
       open_db(p, OPEN_DB_KEEPALIVE);
       if( p->db==0 ){
@@ -8844,6 +8945,7 @@ static int do_meta_command(char *zLine, ShellState *p){
     int bBOM = 0;
     int bOnce = 0;  /* 0: .output, 1: .once, 2: .excel */
 
+    failIfSafeMode(p, "cannot run .%s in safe mode", azArg[0]);
     if( c=='e' ){
       eMode = 'x';
       bOnce = 2;
@@ -9116,6 +9218,7 @@ static int do_meta_command(char *zLine, ShellState *p){
   if( c=='r' && n>=3 && strncmp(azArg[0], "read", n)==0 ){
     FILE *inSaved = p->in;
     int savedLineno = p->lineno;
+    failIfSafeMode(p, "cannot run .read in safe mode");
     if( nArg!=2 ){
       raw_printf(stderr, "Usage: .read FILE\n");
       rc = 1;
@@ -9154,6 +9257,7 @@ static int do_meta_command(char *zLine, ShellState *p){
     sqlite3_backup *pBackup;
     int nTimeout = 0;
 
+    failIfSafeMode(p, "cannot run .restore in safe mode");
     if( nArg==2 ){
       zSrcFile = azArg[1];
       zDb = "main";
@@ -9403,6 +9507,7 @@ static int do_meta_command(char *zLine, ShellState *p){
     */
     if( strcmp(azCmd[0],"changeset")==0 || strcmp(azCmd[0],"patchset")==0 ){
       FILE *out = 0;
+      failIfSafeMode(p, "cannot run \".session %s\" in safe mode", azCmd[0]);
       if( nCmd!=2 ) goto session_syntax_error;
       if( pSession->p==0 ) goto session_not_open;
       out = fopen(azCmd[1], "wb");
@@ -9817,6 +9922,7 @@ static int do_meta_command(char *zLine, ShellState *p){
   ){
     char *zCmd;
     int i, x;
+    failIfSafeMode(p, "cannot run .%s in safe mode", azArg[0]);
     if( nArg<2 ){
       raw_printf(stderr, "Usage: .system COMMAND\n");
       rc = 1;
@@ -10488,6 +10594,7 @@ meta_command_exit:
     p->outCount--;
     if( p->outCount==0 ) output_reset(p);
   }
+  p->bSafeMode = p->bSafeModePersist;
   return rc;
 }
 
@@ -10685,6 +10792,7 @@ static int process_input(ShellState *p){
       }else{
         clearTempFile(p);
       }
+      p->bSafeMode = p->bSafeModePersist;
     }else if( nSql && _all_whitespace(zSql) ){
       if( ShellHasFlag(p, SHFLG_Echo) ) printf("%s\n", zSql);
       nSql = 0;
@@ -10851,10 +10959,12 @@ static const char zOptions[] =
 #endif
   "   -newline SEP         set output row separator. Default: '\\n'\n"
   "   -nofollow            refuse to open symbolic links to database files\n"
+  "   -nonce STRING        set the safe-mode escape nonce\n"
   "   -nullvalue TEXT      set text string for NULL values. Default ''\n"
   "   -pagecache SIZE N    use N slots of SZ bytes each for page cache memory\n"
   "   -quote               set output mode to 'quote'\n"
   "   -readonly            open the database read-only\n"
+  "   -safe                enable safe-mode\n"
   "   -separator SEP       set output column separator. Default: '|'\n"
 #ifdef SQLITE_ENABLE_SORTER_REFERENCES
   "   -sorterref SIZE      sorter references threshold size\n"
@@ -11200,6 +11310,11 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
       sqlite3MemTraceActivate(stderr);
     }else if( strcmp(z,"-bail")==0 ){
       bail_on_error = 1;
+    }else if( strcmp(z,"-nonce")==0 ){
+      free(data.zNonce);
+      data.zNonce = strdup(argv[++i]);
+    }else if( strcmp(z,"-safe")==0 ){
+      /* no-op - catch this on the second pass */
     }
   }
   verify_uninitialized();
@@ -11362,6 +11477,8 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
       i+=2;
     }else if( strcmp(z,"-threadsafe")==0 ){
       i+=2;
+    }else if( strcmp(z,"-nonce")==0 ){
+      i += 2;
     }else if( strcmp(z,"-mmap")==0 ){
       i++;
     }else if( strcmp(z,"-memtrace")==0 ){
@@ -11420,6 +11537,8 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
       readStdin = 0;
       break;
 #endif
+    }else if( strcmp(z,"-safe")==0 ){
+      data.bSafeMode = data.bSafeModePersist = 1;
     }else{
       utf8_printf(stderr,"%s: Error: unknown option: %s\n", Argv0, z);
       raw_printf(stderr,"Use -help for a list of options.\n");
@@ -11522,6 +11641,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
   free(argvToFree);
 #endif
   free(data.colWidth);
+  free(data.zNonce);
   /* Clear the global data structure so that valgrind will detect memory
   ** leaks */
   memset(&data, 0, sizeof(data));