From: drh Date: Wed, 10 Sep 2014 19:01:14 +0000 (+0000) Subject: Add the ".user" shell command and implement the sqlite3_user_add() X-Git-Tag: version-3.8.7~120^2~10 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=f442e33e3a794b198071a9c5f76aa33eb74c3327;p=thirdparty%2Fsqlite.git 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 --- diff --git a/ext/userauth/userauth.h b/ext/userauth/sqlite3userauth.h similarity index 95% rename from ext/userauth/userauth.h rename to ext/userauth/sqlite3userauth.h index 279675f72c..9f95e9fe7a 100644 --- a/ext/userauth/userauth.h +++ b/ext/userauth/sqlite3userauth.h @@ -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 */ ); /* diff --git a/ext/userauth/userauth.c b/ext/userauth/userauth.c index 518f466f14..05d21bf10e 100644 --- a/ext/userauth/userauth.c +++ b/ext/userauth/userauth.c @@ -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; iiauth.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.authLevelauth.authLevelauth.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.authLevelauth.authLevelauth.zAuthUser, zUsername)!=0 - && db->auth.authLevelauth.authLevelauth.authLevelauth.authLevelauth.zAuthUser, zUsername)==0 ) return SQLITE_AUTH; return SQLITE_OK; } diff --git a/main.mk b/main.mk index 2de8a230ff..4a7ac02710 100644 --- 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. diff --git a/manifest b/manifest index fcb6f3314e..28f2b64a45 100644 --- 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 diff --git a/manifest.uuid b/manifest.uuid index cff06d83f6..2ed68f3b13 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c8171ecd0d6f097c9e95d5f6643bae8d67f44750 \ No newline at end of file +a0455f9deb603bf91684158d911269622720fc1a \ No newline at end of file diff --git a/src/func.c b/src/func.c index e338ab842b..94ad1b62da 100644 --- a/src/func.c +++ b/src/func.c @@ -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 ), diff --git a/src/prepare.c b/src/prepare.c index d3531f114b..e1739ba3f6 100644 --- a/src/prepare.c +++ b/src/prepare.c @@ -722,7 +722,7 @@ static int sqlite3LockAndPrepare( db->auth.authLevel = authLevel; } if( db->auth.authLevelmutex); return SQLITE_ERROR; } diff --git a/src/shell.c b/src/shell.c index afe01ef1a1..2312a7d321 100644 --- a/src/shell.c +++ b/src/shell.c @@ -33,6 +33,9 @@ #include #include #include "sqlite3.h" +#if SQLITE_USER_AUTHENTICATION +# include "sqlite3userauth.h" +#endif #include #include @@ -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()); diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 56dede8ba8..e947c3e19a 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -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 diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 0849ee842b..9ef4e36208 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -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 */