Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 6ae7f98

Browse files
ADD: User authentication
* User Authentication Implementation * Rename file to conform to fileformat `sqlite3_*_omit.go` * Updated sqlite3-binding.* with new upgrade tool * Add: callbackRetNil required for error type return because of adding `RegisterFunc`s directly on the connection. * Add: TestCreateAuthDatabase
1 parent 3367a7a commit 6ae7f98

8 files changed

+821
-4
lines changed

‎callback.go‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,8 +331,18 @@ func callbackRetText(ctx *C.sqlite3_context, v reflect.Value) error {
331331
return nil
332332
}
333333

334+
func callbackRetNil(ctx *C.sqlite3_context, v reflect.Value) error {
335+
return nil
336+
}
337+
334338
func callbackRet(typ reflect.Type) (callbackRetConverter, error) {
335339
switch typ.Kind() {
340+
case reflect.Interface:
341+
errorInterface := reflect.TypeOf((*error)(nil)).Elem()
342+
if typ.Implements(errorInterface) {
343+
return callbackRetNil, nil
344+
}
345+
fallthrough
336346
case reflect.Slice:
337347
if typ.Elem().Kind() != reflect.Uint8 {
338348
return nil, errors.New("the only supported slice type is []byte")

‎sqlite3-binding.c‎

Lines changed: 356 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209943,4 +209943,359 @@ SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
209943209943
#else // USE_LIBSQLITE3
209944209944
// If users really want to link against the system sqlite3 we
209945209945
// need to make this file a noop.
209946-
#endif
209946+
#endif
209947+
/*
209948+
** 2014年09月08日
209949+
**
209950+
** The author disclaims copyright to this source code. In place of
209951+
** a legal notice, here is a blessing:
209952+
**
209953+
** May you do good and not evil.
209954+
** May you find forgiveness for yourself and forgive others.
209955+
** May you share freely, never taking more than you give.
209956+
**
209957+
*************************************************************************
209958+
**
209959+
** This file contains the bulk of the implementation of the
209960+
** user-authentication extension feature. Some parts of the user-
209961+
** authentication code are contained within the SQLite core (in the
209962+
** src/ subdirectory of the main source code tree) but those parts
209963+
** that could reasonable be separated out are moved into this file.
209964+
**
209965+
** To compile with the user-authentication feature, append this file to
209966+
** end of an SQLite amalgamation, then add the SQLITE_USER_AUTHENTICATION
209967+
** compile-time option. See the user-auth.txt file in the same source
209968+
** directory as this file for additional information.
209969+
*/
209970+
#ifdef SQLITE_USER_AUTHENTICATION
209971+
#ifndef SQLITEINT_H
209972+
# include "sqliteInt.h"
209973+
#endif
209974+
209975+
/*
209976+
** Prepare an SQL statement for use by the user authentication logic.
209977+
** Return a pointer to the prepared statement on success. Return a
209978+
** NULL pointer if there is an error of any kind.
209979+
*/
209980+
static sqlite3_stmt *sqlite3UserAuthPrepare(
209981+
sqlite3 *db,
209982+
const char *zFormat,
209983+
...
209984+
){
209985+
sqlite3_stmt *pStmt;
209986+
char *zSql;
209987+
int rc;
209988+
va_list ap;
209989+
int savedFlags = db->flags;
209990+
209991+
va_start(ap, zFormat);
209992+
zSql = sqlite3_vmprintf(zFormat, ap);
209993+
va_end(ap);
209994+
if( zSql==0 ) return 0;
209995+
db->flags |= SQLITE_WriteSchema;
209996+
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
209997+
db->flags = savedFlags;
209998+
sqlite3_free(zSql);
209999+
if( rc ){
210000+
sqlite3_finalize(pStmt);
210001+
pStmt = 0;
210002+
}
210003+
return pStmt;
210004+
}
210005+
210006+
/*
210007+
** Check to see if the sqlite_user table exists in database zDb.
210008+
*/
210009+
static int userTableExists(sqlite3 *db, const char *zDb){
210010+
int rc;
210011+
sqlite3_mutex_enter(db->mutex);
210012+
sqlite3BtreeEnterAll(db);
210013+
if( db->init.busy==0 ){
210014+
char *zErr = 0;
210015+
sqlite3Init(db, &zErr);
210016+
sqlite3DbFree(db, zErr);
210017+
}
210018+
rc = sqlite3FindTable(db, "sqlite_user", zDb)!=0;
210019+
sqlite3BtreeLeaveAll(db);
210020+
sqlite3_mutex_leave(db->mutex);
210021+
return rc;
210022+
}
210023+
210024+
/*
210025+
** Check to see if database zDb has a "sqlite_user" table and if it does
210026+
** whether that table can authenticate zUser with nPw,zPw. Write one of
210027+
** the UAUTH_* user authorization level codes into *peAuth and return a
210028+
** result code.
210029+
*/
210030+
static int userAuthCheckLogin(
210031+
sqlite3 *db, /* The database connection to check */
210032+
const char *zDb, /* Name of specific database to check */
210033+
u8 *peAuth /* OUT: One of UAUTH_* constants */
210034+
){
210035+
sqlite3_stmt *pStmt;
210036+
int rc;
210037+
210038+
*peAuth = UAUTH_Unknown;
210039+
if( !userTableExists(db, "main") ){
210040+
*peAuth = UAUTH_Admin; /* No sqlite_user table. Everybody is admin. */
210041+
return SQLITE_OK;
210042+
}
210043+
if( db->auth.zAuthUser==0 ){
210044+
*peAuth = UAUTH_Fail;
210045+
return SQLITE_OK;
210046+
}
210047+
pStmt = sqlite3UserAuthPrepare(db,
210048+
"SELECT pw=sqlite_crypt(?1,pw), isAdmin FROM \"%w\".sqlite_user"
210049+
" WHERE uname=?2", zDb);
210050+
if( pStmt==0 ) return SQLITE_NOMEM;
210051+
sqlite3_bind_blob(pStmt, 1, db->auth.zAuthPW, db->auth.nAuthPW,SQLITE_STATIC);
210052+
sqlite3_bind_text(pStmt, 2, db->auth.zAuthUser, -1, SQLITE_STATIC);
210053+
rc = sqlite3_step(pStmt);
210054+
if( rc==SQLITE_ROW && sqlite3_column_int(pStmt,0) ){
210055+
*peAuth = sqlite3_column_int(pStmt, 1) + UAUTH_User;
210056+
}else{
210057+
*peAuth = UAUTH_Fail;
210058+
}
210059+
return sqlite3_finalize(pStmt);
210060+
}
210061+
int sqlite3UserAuthCheckLogin(
210062+
sqlite3 *db, /* The database connection to check */
210063+
const char *zDb, /* Name of specific database to check */
210064+
u8 *peAuth /* OUT: One of UAUTH_* constants */
210065+
){
210066+
int rc;
210067+
u8 savedAuthLevel;
210068+
assert( zDb!=0 );
210069+
assert( peAuth!=0 );
210070+
savedAuthLevel = db->auth.authLevel;
210071+
db->auth.authLevel = UAUTH_Admin;
210072+
rc = userAuthCheckLogin(db, zDb, peAuth);
210073+
db->auth.authLevel = savedAuthLevel;
210074+
return rc;
210075+
}
210076+
210077+
/*
210078+
** If the current authLevel is UAUTH_Unknown, the take actions to figure
210079+
** out what authLevel should be
210080+
*/
210081+
void sqlite3UserAuthInit(sqlite3 *db){
210082+
if( db->auth.authLevel==UAUTH_Unknown ){
210083+
u8 authLevel = UAUTH_Fail;
210084+
sqlite3UserAuthCheckLogin(db, "main", &authLevel);
210085+
db->auth.authLevel = authLevel;
210086+
if( authLevel<UAUTH_Admin ) db->flags &= ~SQLITE_WriteSchema;
210087+
}
210088+
}
210089+
210090+
/*
210091+
** Implementation of the sqlite_crypt(X,Y) function.
210092+
**
210093+
** If Y is NULL then generate a new hash for password X and return that
210094+
** hash. If Y is not null, then generate a hash for password X using the
210095+
** same salt as the previous hash Y and return the new hash.
210096+
*/
210097+
void sqlite3CryptFunc(
210098+
sqlite3_context *context,
210099+
int NotUsed,
210100+
sqlite3_value **argv
210101+
){
210102+
const char *zIn;
210103+
int nIn, ii;
210104+
u8 *zOut;
210105+
char zSalt[8];
210106+
zIn = sqlite3_value_blob(argv[0]);
210107+
nIn = sqlite3_value_bytes(argv[0]);
210108+
if( sqlite3_value_type(argv[1])==SQLITE_BLOB
210109+
&& sqlite3_value_bytes(argv[1])==nIn+sizeof(zSalt)
210110+
){
210111+
memcpy(zSalt, sqlite3_value_blob(argv[1]), sizeof(zSalt));
210112+
}else{
210113+
sqlite3_randomness(sizeof(zSalt), zSalt);
210114+
}
210115+
zOut = sqlite3_malloc( nIn+sizeof(zSalt) );
210116+
if( zOut==0 ){
210117+
sqlite3_result_error_nomem(context);
210118+
}else{
210119+
memcpy(zOut, zSalt, sizeof(zSalt));
210120+
for(ii=0; ii<nIn; ii++){
210121+
zOut[ii+sizeof(zSalt)] = zIn[ii]^zSalt[ii&0x7];
210122+
}
210123+
sqlite3_result_blob(context, zOut, nIn+sizeof(zSalt), sqlite3_free);
210124+
}
210125+
}
210126+
210127+
/*
210128+
** If a database contains the SQLITE_USER table, then the
210129+
** sqlite3_user_authenticate() interface must be invoked with an
210130+
** appropriate username and password prior to enable read and write
210131+
** access to the database.
210132+
**
210133+
** Return SQLITE_OK on success or SQLITE_ERROR if the username/password
210134+
** combination is incorrect or unknown.
210135+
**
210136+
** If the SQLITE_USER table is not present in the database file, then
210137+
** this interface is a harmless no-op returnning SQLITE_OK.
210138+
*/
210139+
int sqlite3_user_authenticate(
210140+
sqlite3 *db, /* The database connection */
210141+
const char *zUsername, /* Username */
210142+
const char *zPW, /* Password or credentials */
210143+
int nPW /* Number of bytes in aPW[] */
210144+
){
210145+
int rc;
210146+
u8 authLevel = UAUTH_Fail;
210147+
db->auth.authLevel = UAUTH_Unknown;
210148+
sqlite3_free(db->auth.zAuthUser);
210149+
sqlite3_free(db->auth.zAuthPW);
210150+
memset(&db->auth, 0, sizeof(db->auth));
210151+
db->auth.zAuthUser = sqlite3_mprintf("%s", zUsername);
210152+
if( db->auth.zAuthUser==0 ) return SQLITE_NOMEM;
210153+
db->auth.zAuthPW = sqlite3_malloc( nPW+1 );
210154+
if( db->auth.zAuthPW==0 ) return SQLITE_NOMEM;
210155+
memcpy(db->auth.zAuthPW,zPW,nPW);
210156+
db->auth.nAuthPW = nPW;
210157+
rc = sqlite3UserAuthCheckLogin(db, "main", &authLevel);
210158+
db->auth.authLevel = authLevel;
210159+
sqlite3ExpirePreparedStatements(db);
210160+
if( rc ){
210161+
return rc; /* OOM error, I/O error, etc. */
210162+
}
210163+
if( authLevel<UAUTH_User ){
210164+
return SQLITE_AUTH; /* Incorrect username and/or password */
210165+
}
210166+
return SQLITE_OK; /* Successful login */
210167+
}
210168+
210169+
/*
210170+
** The sqlite3_user_add() interface can be used (by an admin user only)
210171+
** to create a new user. When called on a no-authentication-required
210172+
** database, this routine converts the database into an authentication-
210173+
** required database, automatically makes the added user an
210174+
** administrator, and logs in the current connection as that user.
210175+
** The sqlite3_user_add() interface only works for the "main" database, not
210176+
** for any ATTACH-ed databases. Any call to sqlite3_user_add() by a
210177+
** non-admin user results in an error.
210178+
*/
210179+
int sqlite3_user_add(
210180+
sqlite3 *db, /* Database connection */
210181+
const char *zUsername, /* Username to be added */
210182+
const char *aPW, /* Password or credentials */
210183+
int nPW, /* Number of bytes in aPW[] */
210184+
int isAdmin /* True to give new user admin privilege */
210185+
){
210186+
sqlite3_stmt *pStmt;
210187+
int rc;
210188+
sqlite3UserAuthInit(db);
210189+
if( db->auth.authLevel<UAUTH_Admin ) return SQLITE_AUTH;
210190+
if( !userTableExists(db, "main") ){
210191+
if( !isAdmin ) return SQLITE_AUTH;
210192+
pStmt = sqlite3UserAuthPrepare(db,
210193+
"CREATE TABLE sqlite_user(\n"
210194+
" uname TEXT PRIMARY KEY,\n"
210195+
" isAdmin BOOLEAN,\n"
210196+
" pw BLOB\n"
210197+
") WITHOUT ROWID;");
210198+
if( pStmt==0 ) return SQLITE_NOMEM;
210199+
sqlite3_step(pStmt);
210200+
rc = sqlite3_finalize(pStmt);
210201+
if( rc ) return rc;
210202+
}
210203+
pStmt = sqlite3UserAuthPrepare(db,
210204+
"INSERT INTO sqlite_user(uname,isAdmin,pw)"
210205+
" VALUES(%Q,%d,sqlite_crypt(?1,NULL))",
210206+
zUsername, isAdmin!=0);
210207+
if( pStmt==0 ) return SQLITE_NOMEM;
210208+
sqlite3_bind_blob(pStmt, 1, aPW, nPW, SQLITE_STATIC);
210209+
sqlite3_step(pStmt);
210210+
rc = sqlite3_finalize(pStmt);
210211+
if( rc ) return rc;
210212+
if( db->auth.zAuthUser==0 ){
210213+
assert( isAdmin!=0 );
210214+
sqlite3_user_authenticate(db, zUsername, aPW, nPW);
210215+
}
210216+
return SQLITE_OK;
210217+
}
210218+
210219+
/*
210220+
** The sqlite3_user_change() interface can be used to change a users
210221+
** login credentials or admin privilege. Any user can change their own
210222+
** login credentials. Only an admin user can change another users login
210223+
** credentials or admin privilege setting. No user may change their own
210224+
** admin privilege setting.
210225+
*/
210226+
int sqlite3_user_change(
210227+
sqlite3 *db, /* Database connection */
210228+
const char *zUsername, /* Username to change */
210229+
const char *aPW, /* Modified password or credentials */
210230+
int nPW, /* Number of bytes in aPW[] */
210231+
int isAdmin /* Modified admin privilege for the user */
210232+
){
210233+
sqlite3_stmt *pStmt;
210234+
int rc;
210235+
u8 authLevel;
210236+
210237+
authLevel = db->auth.authLevel;
210238+
if( authLevel<UAUTH_User ){
210239+
/* Must be logged in to make a change */
210240+
return SQLITE_AUTH;
210241+
}
210242+
if( strcmp(db->auth.zAuthUser, zUsername)!=0 ){
210243+
if( db->auth.authLevel<UAUTH_Admin ){
210244+
/* Must be an administrator to change a different user */
210245+
return SQLITE_AUTH;
210246+
}
210247+
}else if( isAdmin!=(authLevel==UAUTH_Admin) ){
210248+
/* Cannot change the isAdmin setting for self */
210249+
return SQLITE_AUTH;
210250+
}
210251+
db->auth.authLevel = UAUTH_Admin;
210252+
if( !userTableExists(db, "main") ){
210253+
/* This routine is a no-op if the user to be modified does not exist */
210254+
}else{
210255+
pStmt = sqlite3UserAuthPrepare(db,
210256+
"UPDATE sqlite_user SET isAdmin=%d, pw=sqlite_crypt(?1,NULL)"
210257+
" WHERE uname=%Q", isAdmin, zUsername);
210258+
if( pStmt==0 ){
210259+
rc = SQLITE_NOMEM;
210260+
}else{
210261+
sqlite3_bind_blob(pStmt, 1, aPW, nPW, SQLITE_STATIC);
210262+
sqlite3_step(pStmt);
210263+
rc = sqlite3_finalize(pStmt);
210264+
}
210265+
}
210266+
db->auth.authLevel = authLevel;
210267+
return rc;
210268+
}
210269+
210270+
/*
210271+
** The sqlite3_user_delete() interface can be used (by an admin user only)
210272+
** to delete a user. The currently logged-in user cannot be deleted,
210273+
** which guarantees that there is always an admin user and hence that
210274+
** the database cannot be converted into a no-authentication-required
210275+
** database.
210276+
*/
210277+
int sqlite3_user_delete(
210278+
sqlite3 *db, /* Database connection */
210279+
const char *zUsername /* Username to remove */
210280+
){
210281+
sqlite3_stmt *pStmt;
210282+
if( db->auth.authLevel<UAUTH_Admin ){
210283+
/* Must be an administrator to delete a user */
210284+
return SQLITE_AUTH;
210285+
}
210286+
if( strcmp(db->auth.zAuthUser, zUsername)==0 ){
210287+
/* Cannot delete self */
210288+
return SQLITE_AUTH;
210289+
}
210290+
if( !userTableExists(db, "main") ){
210291+
/* This routine is a no-op if the user to be deleted does not exist */
210292+
return SQLITE_OK;
210293+
}
210294+
pStmt = sqlite3UserAuthPrepare(db,
210295+
"DELETE FROM sqlite_user WHERE uname=%Q", zUsername);
210296+
if( pStmt==0 ) return SQLITE_NOMEM;
210297+
sqlite3_step(pStmt);
210298+
return sqlite3_finalize(pStmt);
210299+
}
210300+
210301+
#endif /* SQLITE_USER_AUTHENTICATION */

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /