]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add the ".user" shell command and implement the sqlite3_user_add()
authordrh <drh@noemail.net>
Wed, 10 Sep 2014 19:01:14 +0000 (19:01 +0000)
committerdrh <drh@noemail.net>
Wed, 10 Sep 2014 19:01:14 +0000 (19:01 +0000)
routine.  Incremental check-in.  The code compiles but does not work.

FossilOrigin-Name: a0455f9deb603bf91684158d911269622720fc1a

ext/userauth/sqlite3userauth.h [moved from ext/userauth/userauth.h with 95% similarity]
ext/userauth/userauth.c
main.mk
manifest
manifest.uuid
src/func.c
src/prepare.c
src/shell.c
src/sqlite.h.in
src/sqliteInt.h

similarity index 95%
rename from ext/userauth/userauth.h
rename to ext/userauth/sqlite3userauth.h
index 279675f72cc5eddb669d54d56604d1bbdde0c1ba..9f95e9fe7a10b7a5295666063133d458e8693f48 100644 (file)
@@ -37,7 +37,7 @@ int sqlite3_user_authenticate(
   sqlite3 *db,           /* The database connection */
   const char *zUsername, /* Username */
   int nPW,               /* Number of bytes in aPW[] */
-  const void *aPW        /* Password or credentials */
+  const char *aPW        /* Password or credentials */
 );
 
 /*
@@ -55,7 +55,7 @@ int sqlite3_user_add(
   const char *zUsername, /* Username to be added */
   int isAdmin,           /* True to give new user admin privilege */
   int nPW,               /* Number of bytes in aPW[] */
-  const void *aPW        /* Password or credentials */
+  const char *aPW        /* Password or credentials */
 );
 
 /*
@@ -70,7 +70,7 @@ int sqlite3_user_change(
   const char *zUsername, /* Username to change */
   int isAdmin,           /* Modified admin privilege for the user */
   int nPW,               /* Number of bytes in aPW[] */
-  const void *aPW        /* Modified password or credentials */
+  const char *aPW        /* Modified password or credentials */
 );
 
 /*
index 518f466f143535d6eff91a803b3a62261a1917a7..05d21bf10eeff768ef2e69ed8192a0ae9f03b5a4 100644 (file)
@@ -23,6 +23,7 @@
 */
 #ifdef SQLITE_USER_AUTHENTICATION
 #include "sqliteInt.h"
+#include "sqlite3userauth.h"
 
 /*
 ** Prepare an SQL statement for use by the user authentication logic.
@@ -52,6 +53,19 @@ static sqlite3_stmt *sqlite3UserAuthPrepare(
   return pStmt;
 }
 
+/*
+** Check to see if the sqlite_user table exists in database zDb.
+*/
+static int userTableExists(sqlite3 *db, const char *zDb){
+  int rc;
+  sqlite3_mutex_enter(db->mutex);
+  sqlite3BtreeEnterAll(db);
+  rc = sqlite3FindTable(db, "sqlite_user", zDb)!=0;
+  sqlite3BtreeLeaveAll(db);
+  sqlite3_mutex_leave(db->mutex);
+  return rc;
+}
+
 /*
 ** Check to see if database zDb has a "sqlite_user" table and if it does
 ** whether that table can authenticate zUser with nPw,zPw.  Write one of
@@ -67,20 +81,8 @@ static int userAuthCheckLogin(
   int rc;
 
   *peAuth = UAUTH_Unknown;
-  pStmt = sqlite3UserAuthPrepare(db, 
-              "SELECT 1 FROM \"%w\".sqlite_master "
-              " WHERE name='sqlite_user' AND type='table'", zDb);
-  if( pStmt==0 ){
-    return SQLITE_NOMEM;
-  }
-  rc = sqlite3_step(pStmt);
-  sqlite3_finalize(pStmt);
-  if( rc==SQLITE_DONE ){
+  if( !userTableExists(db, "main") ){
     *peAuth = UAUTH_Admin;  /* No sqlite_user table.  Everybody is admin. */
-    return SQLITE_OK;
-  }
-  if( rc!=SQLITE_ROW ){
-    return rc;
   }
   if( db->auth.zAuthUser==0 ){
     *peAuth = UAUTH_Fail;
@@ -115,6 +117,42 @@ int sqlite3UserAuthCheckLogin(
   return rc;
 }
 
+/*
+** Implementation of the sqlite_crypt(X,Y) function.
+**
+** If Y is NULL then generate a new hash for password X and return that
+** hash.  If Y is not null, then generate a hash for password X using the
+** same salt as the previous hash Y and return the new hash.
+*/
+void sqlite3CryptFunc(
+  sqlite3_context *context,
+  int NotUsed,
+  sqlite3_value **argv
+){
+  const char *zIn;
+  int nIn, ii;
+  u8 *zOut;
+  char zSalt[8];
+  zIn = sqlite3_value_blob(argv[0]);
+  nIn = sqlite3_value_bytes(argv[0]);
+  if( sqlite3_value_type(argv[1])==SQLITE_BLOB
+   && sqlite3_value_bytes(argv[1])==nIn+sizeof(zSalt)
+  ){
+    memcpy(zSalt, sqlite3_value_blob(argv[1]), sizeof(zSalt));
+  }else{
+    sqlite3_randomness(sizeof(zSalt), zSalt);
+  }
+  zOut = sqlite3_malloc( nIn+sizeof(zSalt) );
+  if( zOut==0 ){
+    sqlite3_result_error_nomem(context);
+  }else{
+    memcpy(zOut, zSalt, sizeof(zSalt));
+    for(ii=0; ii<nIn; ii++){
+      zOut[ii+sizeof(zSalt)] = zIn[ii]^zSalt[ii&0x7];
+    }
+    sqlite3_result_blob(context, zOut, nIn+sizeof(zSalt), sqlite3_free);
+  }
+}
 
 /*
 ** If a database contains the SQLITE_USER table, then the
@@ -148,6 +186,7 @@ int sqlite3_user_authenticate(
   db->auth.nAuthPW = nPW;
   rc = sqlite3UserAuthCheckLogin(db, "main", &authLevel);
   db->auth.authLevel = authLevel;
+  sqlite3ExpirePreparedStatements(db);
   if( rc ){
     return rc;           /* OOM error, I/O error, etc. */
   }
@@ -172,9 +211,37 @@ int sqlite3_user_add(
   const char *zUsername, /* Username to be added */
   int isAdmin,           /* True to give new user admin privilege */
   int nPW,               /* Number of bytes in aPW[] */
-  const void *aPW        /* Password or credentials */
+  const char *aPW        /* Password or credentials */
 ){
-  if( db->auth.authLevel<UAUTH_Admin ) return SQLITE_ERROR;
+  sqlite3_stmt *pStmt;
+  int rc;
+  if( db->auth.authLevel<UAUTH_Admin ) return SQLITE_AUTH;
+  if( !userTableExists(db, "main") ){
+    if( !isAdmin ) return SQLITE_AUTH;
+    pStmt = sqlite3UserAuthPrepare(db, 
+              "CREATE TABLE sqlite_user(\n"
+              "  uname TEXT PRIMARY KEY,\n"
+              "  isAdmin BOOLEAN,\n"
+              "  pw BLOB\n"
+              ") WITHOUT ROWID;");
+    if( pStmt==0 ) return SQLITE_NOMEM;
+    sqlite3_step(pStmt);
+    rc = sqlite3_finalize(pStmt);
+    if( rc ) return rc;
+  }
+  pStmt = sqlite3UserAuthPrepare(db, 
+            "INSERT INTO sqlite_user(uname,isAdmin,sqlite_crypt(pw,NULL))"
+            " VALUES(%Q,%d,?1)",
+            zUsername, isAdmin!=0);
+  if( pStmt==0 ) return SQLITE_NOMEM;
+  sqlite3_bind_blob(pStmt, 1, aPW, nPW, SQLITE_STATIC);
+  sqlite3_step(pStmt);
+  rc = sqlite3_finalize(pStmt);
+  if( rc ) return rc;
+  if( db->auth.zAuthUser==0 ){
+    assert( isAdmin!=0 );
+    sqlite3_user_authenticate(db, zUsername, nPW, aPW);
+  }
   return SQLITE_OK;
 }
 
@@ -190,11 +257,11 @@ int sqlite3_user_change(
   const char *zUsername, /* Username to change */
   int isAdmin,           /* Modified admin privilege for the user */
   int nPW,               /* Number of bytes in aPW[] */
-  const void *aPW        /* Modified password or credentials */
+  const char *aPW        /* Modified password or credentials */
 ){
-  if( db->auth.authLevel<UAUTH_User ) return SQLITE_ERROR;
+  if( db->auth.authLevel<UAUTH_User ) return SQLITE_AUTH;
   if( strcmp(db->auth.zAuthUser, zUsername)!=0
-       && db->auth.authLevel<UAUTH_Admin ) return SQLITE_ERROR;
+       && db->auth.authLevel<UAUTH_Admin ) return SQLITE_AUTH;
   return SQLITE_OK;
 }
 
@@ -209,7 +276,8 @@ int sqlite3_user_delete(
   sqlite3 *db,           /* Database connection */
   const char *zUsername  /* Username to remove */
 ){
-  if( db->auth.authLevel<UAUTH_Admin ) return SQLITE_ERROR;
+  if( db->auth.authLevel<UAUTH_Admin ) return SQLITE_AUTH;
+  if( strcmp(db->auth.zAuthUser, zUsername)==0 ) return SQLITE_AUTH;
   return SQLITE_OK;
 }
 
diff --git a/main.mk b/main.mk
index 2de8a230ff27d461b4f7dd186c990acdd38ce401..4a7ac02710bf841c6ca4a4976e13cdfaf42f935f 100644 (file)
--- a/main.mk
+++ b/main.mk
@@ -46,7 +46,7 @@
 #
 TCCX =  $(TCC) $(OPTS) -I. -I$(TOP)/src -I$(TOP) 
 TCCX += -I$(TOP)/ext/rtree -I$(TOP)/ext/icu -I$(TOP)/ext/fts3
-TCCX += -I$(TOP)/ext/async
+TCCX += -I$(TOP)/ext/async -I$(TOP)/ext/userauth
 
 # Object files for the SQLite library.
 #
@@ -216,7 +216,7 @@ SRC += \
   $(TOP)/ext/rtree/rtree.c
 SRC += \
   $(TOP)/ext/userauth/userauth.c \
-  $(TOP)/ext/userauth/userauth.h
+  $(TOP)/ext/userauth/sqlite3userauth.h
 
 # Generated source code files
 #
@@ -380,7 +380,7 @@ EXTHDR += \
 EXTHDR += \
   $(TOP)/ext/icu/sqliteicu.h
 EXTHDR += \
-  $(TOP)/ext/userauth/userauth.h
+  $(TOP)/ext/userauth/sqlite3userauth.h
 
 # This is the default Makefile target.  The objects listed here
 # are what get build when you type just "make" with no arguments.
index fcb6f3314e539751ccd36c37c02a7f50484deb49..28f2b64a45c8ef745873ccc699871a8edfb48edc 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Further\sideas\son\suser\sauthentication.\s\sNot\syet\sworking\scode.
-D 2014-09-10T17:34:28.937
+C Add\sthe\s".user"\sshell\scommand\sand\simplement\sthe\ssqlite3_user_add()\nroutine.\s\sIncremental\scheck-in.\s\sThe\scode\scompiles\sbut\sdoes\snot\swork.
+D 2014-09-10T19:01:14.206
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -144,13 +144,13 @@ F ext/rtree/rtree_util.tcl 06aab2ed5b826545bf215fff90ecb9255a8647ea
 F ext/rtree/sqlite3rtree.h 83349d519fe5f518b3ea025d18dd1fe51b1684bd
 F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de
 F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
+F ext/userauth/sqlite3userauth.h 6e15b0006e7b07b7b008c9f9297b3781a7514337 w ext/userauth/userauth.h
 F ext/userauth/user-auth.txt f471c5a363ab0682b109d85982ea857f9a144ccc
-F ext/userauth/userauth.c 0d24bcd4a18b354797b9cc6f8e4ba152d385cebe
-F ext/userauth/userauth.h efbfb68ff083749ad63b12dcb5877b936c3458d6
+F ext/userauth/userauth.c 5a3f8a7ac79eb1315c7e0313ff87d8c30e33d837
 F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
 F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
 F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
-F main.mk ac53fd5d61941c0ff1f05e710999b64ffd03f069
+F main.mk bbc8b6000ed143a1a8d31d3b4995c359a3188fa1
 F mkopcodec.awk c2ff431854d702cdd2d779c9c0d1f58fa16fa4ea
 F mkopcodeh.awk c6b3fa301db6ef7ac916b14c60868aeaec1337b5
 F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
@@ -183,7 +183,7 @@ F src/delete.c fae81cc2eb14b75267d4f47d3cfc9ae02aae726f
 F src/expr.c 441a7e24e2f7bea9475778fa8acce9e8a69ca8f0
 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
 F src/fkey.c da985ae673efef2c712caef825a5d2edb087ead7
-F src/func.c 0517037766e18eff7dce298e6b3a8e6311df75ec
+F src/func.c 1b7ac915eb83255eba90906cc2e317b1f29ae5c9
 F src/global.c 5110fa12e09729b84eee0191c984ec4008e21937
 F src/hash.c 4263fbc955f26c2e8cdc0cf214bc42435aa4e4f5
 F src/hash.h c8f3c31722cf3277d03713909761e152a5b81094
@@ -221,17 +221,17 @@ F src/pcache.c 2048affdb09a04478b5fc6e64cb1083078d369be
 F src/pcache.h 9b559127b83f84ff76d735c8262f04853be0c59a
 F src/pcache1.c dab8ab930d4a73b99768d881185994f34b80ecaa
 F src/pragma.c 3b7b1a5e90804006f44c65464c7032ee6a1d24e3
-F src/prepare.c 51ca716a2f73364d8f57c69c89423a0831d17572
+F src/prepare.c 8c2f992a3b3949ab0bf9d4862f7a271f0af0bd5b
 F src/printf.c e74925089a85e3c9f0e315595f41c139d3d118c2
 F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece
 F src/resolve.c 0d1621e45fffe4b4396477cf46e41a84b0145ffb
 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e
 F src/select.c b4457526cee73c0b69fad42f799f619b1d5a8a8a
-F src/shell.c 713cef4d73c05fc8e12f4960072329d767a05d50
-F src/sqlite.h.in 64a77f2822f1325b12050972003184f99b655a0f
+F src/shell.c 4dac2ec625fb15a51b06ab998e7cec8c1e6a40eb
+F src/sqlite.h.in 577876beef2264a0b031c0d744c81855983088f9
 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad
 F src/sqlite3ext.h 1f40357fb9b12a80c5a3b2b109fd249b009213d4
-F src/sqliteInt.h 10a1f056b6b40449a81cf5d708bc0d9fac053c53
+F src/sqliteInt.h fdc23ef0c5475888d0e532204a7451507ce17206
 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
 F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
 F src/table.c 4e28a53e66bad8d014a510ef0205f5497c712b08
@@ -1196,7 +1196,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P 8440f093bac19a41d44ee352744354eab897fe4e
-R 6f268f8f48a352ef36f94cb71204780d
+P c8171ecd0d6f097c9e95d5f6643bae8d67f44750
+R f252935e505dbc9ddcbfc78d0487cc51
 U drh
-Z 6484e1728dcc8ed1c2a7dbcf5e6f2393
+Z 5adba3159d6bf335715850631d1526a9
index cff06d83f6fb5a1cf293555b98d4a86431831a03..2ed68f3b13b905321450d6a62f5bd8e89b728552 100644 (file)
@@ -1 +1 @@
-c8171ecd0d6f097c9e95d5f6643bae8d67f44750
\ No newline at end of file
+a0455f9deb603bf91684158d911269622720fc1a
\ No newline at end of file
index e338ab842bc4db4c7b9b295255c6ef8d96205f39..94ad1b62da397287e1e05aef93551d105b2985bf 100644 (file)
@@ -1695,6 +1695,9 @@ void sqlite3RegisterGlobalFunctions(void){
     FUNCTION(sqlite_version,     0, 0, 0, versionFunc      ),
     FUNCTION(sqlite_source_id,   0, 0, 0, sourceidFunc     ),
     FUNCTION(sqlite_log,         2, 0, 0, errlogFunc       ),
+#if SQLITE_USER_AUTHENTICATION
+    FUNCTION(sqlite_crypt,       2, 0, 0, sqlite3CryptFunc ),
+#endif
 #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
     FUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc  ),
     FUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc  ),
index d3531f114b7d17c747d49168eb4901e803bf0bf9..e1739ba3f6eabc1a7af122ba772671b5d544a4ae 100644 (file)
@@ -722,7 +722,7 @@ static int sqlite3LockAndPrepare(
       db->auth.authLevel = authLevel;
     }
     if( db->auth.authLevel<UAUTH_User ){
-      sqlite3ErrorWithMsg(db, SQLITE_ERROR, "user not authenticated");
+      sqlite3ErrorWithMsg(db, SQLITE_AUTH_USER, "user not authenticated");
       sqlite3_mutex_leave(db->mutex);
       return SQLITE_ERROR;
     }
index afe01ef1a16f5f8d4c3ac6f6c267049d21fa91c8..2312a7d32143b59d87a9217b42e5f0300f0be1a0 100644 (file)
@@ -33,6 +33,9 @@
 #include <stdio.h>
 #include <assert.h>
 #include "sqlite3.h"
+#if SQLITE_USER_AUTHENTICATION
+# include "sqlite3userauth.h"
+#endif
 #include <ctype.h>
 #include <stdarg.h>
 
@@ -3435,6 +3438,67 @@ static int do_meta_command(char *zLine, ShellState *p){
 #endif
   }else
 
+#if SQLITE_USER_AUTHENTICATION
+  if( c=='u' && strncmp(azArg[0], "user", n)==0 ){
+    if( nArg<2 ){
+      fprintf(stderr, "Usage: .user SUBCOMMAND ...\n");
+      rc = 1;
+      goto meta_command_exit;
+    }
+    if( strcmp(azArg[1],"login")==0 ){
+      if( nArg!=4 ){
+        fprintf(stderr, "Usage: .user login USER PASSWORD\n");
+        rc = 1;
+        goto meta_command_exit;
+      }
+      rc = sqlite3_user_authenticate(p->db, azArg[2], (int)strlen(azArg[3]), azArg[3]);
+      if( rc ){
+        fprintf(stderr, "Authentication failed for user %s\n", azArg[2]);
+        rc = 1;
+      }
+    }else if( strcmp(azArg[1],"add")==0 ){
+      if( nArg!=5 ){
+        fprintf(stderr, "Usage: .user add USER ISADMIN PASSWORD\n");
+        rc = 1;
+        goto meta_command_exit;
+      }
+      rc = sqlite3_user_add(p->db, azArg[2], booleanValue(azArg[3]),
+                            (int)strlen(azArg[4]), azArg[4]);
+      if( rc ){
+        fprintf(stderr, "User-Add failed: %d\n", rc);
+        rc = 1;
+      }
+    }else if( strcmp(azArg[1],"edit")==0 ){
+      if( nArg!=5 ){
+        fprintf(stderr, "Usage: .user edit USER ISADMIN PASSWORD\n");
+        rc = 1;
+        goto meta_command_exit;
+      }
+      rc = sqlite3_user_change(p->db, azArg[2], booleanValue(azArg[3]),
+                              (int)strlen(azArg[4]), azArg[4]);
+      if( rc ){
+        fprintf(stderr, "User-Edit failed: %d\n", rc);
+        rc = 1;
+      }
+    }else if( strcmp(azArg[1],"delete")==0 ){
+      if( nArg!=3 ){
+        fprintf(stderr, "Usage: .user delete USER\n");
+        rc = 1;
+        goto meta_command_exit;
+      }
+      rc = sqlite3_user_delete(p->db, azArg[2]);
+      if( rc ){
+        fprintf(stderr, "User-Delete failed: %d\n", rc);
+        rc = 1;
+      }
+    }else{
+      fprintf(stderr, "Usage: .user login|add|edit|delete ...\n");
+      rc = 1;
+      goto meta_command_exit;
+    }    
+  }else
+#endif /* SQLITE_USER_AUTHENTICATION */
+
   if( c=='v' && strncmp(azArg[0], "version", n)==0 ){
     fprintf(p->out, "SQLite %s %s\n" /*extra-version-info*/,
         sqlite3_libversion(), sqlite3_sourceid());
index 56dede8ba8477c5a185e419c831348acc4833e5e..e947c3e19aecb90a79f25731c7d54b4a2326b6be 100644 (file)
@@ -492,6 +492,7 @@ int sqlite3_exec(
 #define SQLITE_NOTICE_RECOVER_WAL      (SQLITE_NOTICE | (1<<8))
 #define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8))
 #define SQLITE_WARNING_AUTOINDEX       (SQLITE_WARNING | (1<<8))
+#define SQLITE_AUTH_USER               (SQLITE_AUTH | (1<<8))
 
 /*
 ** CAPI3REF: Flags For File Open Operations
index 0849ee842b1b800e195d1c42b96b3bfe5afba305..9ef4e362086effe1003ac280c845f1658fee134b 100644 (file)
@@ -1010,6 +1010,8 @@ struct sqlite3_userauth {
 /* Functions used only by user authorization logic */
 int sqlite3UserAuthTable(const char*);
 int sqlite3UserAuthCheckLogin(sqlite3*,const char*,u8*);
+void sqlite3CryptFunc(sqlite3_context*,int,sqlite3_value**);
+
 
 #endif /* SQLITE_USER_AUTHENTICATION */