Add the ".user" shell command and implement the sqlite3_user_add()

routine.  Incremental check-in.  The code compiles but does not work.

FossilOrigin-Name: a0455f9deb603bf91684158d911269622720fc1a
This commit is contained in:
drh 2014-09-10 19:01:14 +00:00
parent e933b83f02
commit f442e33e3a
10 changed files with 178 additions and 40 deletions

View 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 */
);
/*

View 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;
}

View File

@ -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.

View File

@ -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

View File

@ -1 +1 @@
c8171ecd0d6f097c9e95d5f6643bae8d67f44750
a0455f9deb603bf91684158d911269622720fc1a

View 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 ),

View 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;
}

View 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());

View 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

View 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 */