Index: ext/userauth/userauth.c ================================================================== --- ext/userauth/userauth.c +++ ext/userauth/userauth.c @@ -20,10 +20,11 @@ ** end of an SQLite amalgamation, then add the SQLITE_USER_AUTHENTICATION ** compile-time option. See the user-auth.txt file in the same source ** directory as this file for additional information. */ #ifdef SQLITE_USER_AUTHENTICATION +#include "sqliteInt.h" /* ** Prepare an SQL statement for use by the user authentication logic. ** Return a pointer to the prepared statement on success. Return a ** NULL pointer if there is an error of any kind. @@ -40,14 +41,11 @@ va_start(ap, zFormat); zSql = sqlite3_vmprintf(zFormat, ap); va_end(ap); if( zSql==0 ) return 0; - savedFlags = db->auth.authFlags; - db->auth.authFlags |= UAUTH_Ovrd; rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); - db->auth.authFlags = savedFlags; sqlite3_free(zSql); if( rc ){ sqlite3_finalize(pStmt); pStmt = 0; } @@ -54,53 +52,71 @@ return pStmt; } /* ** Check to see if database zDb has a "sqlite_user" table and if it does -** whether that table can authenticate zUser with nPw,zPw. +** whether that table can authenticate zUser with nPw,zPw. Write one of +** the UAUTH_* user authorization level codes into *peAuth and return a +** result code. */ -static int sqlite3UserAuthCheckLogin( +static int userAuthCheckLogin( sqlite3 *db, /* The database connection to check */ const char *zDb, /* Name of specific database to check */ - const char *zUser, /* User name */ - int nPw, /* Size of password in bytes */ - const char *zPw, /* Password */ - int *pbOk /* OUT: write boolean result here */ + u8 *peAuth /* OUT: One of UAUTH_* constants */ ){ sqlite3_stmt *pStmt; - char *zSql; int rc; - int iResult; - *pbOk = 0; - iResult = 0; + *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): + if( pStmt==0 ){ + return SQLITE_NOMEM; + } + rc = sqlite3_step(pStmt); sqlite3_finalize(pStmt); if( rc==SQLITE_DONE ){ - *pbOk = 1; + *peAuth = UAUTH_Admin; /* No sqlite_user table. Everybody is admin. */ return SQLITE_OK; } - if( rc!=SQLITE_OK ){ + if( rc!=SQLITE_ROW ){ return rc; + } + if( db->auth.zAuthUser==0 ){ + *peAuth = UAUTH_Fail; + return SQLITE_OK; } pStmt = sqlite3UserAuthPrepare(db, "SELECT pw=sqlite_crypt(?1,pw), isAdmin FROM \"%w\".sqlite_user" " WHERE uname=?2", zDb); if( pStmt==0 ) return SQLITE_NOMEM; - sqlite3_bind_blob(pStmt, 1, zPw, nPw, SQLITE_STATIC); - sqlite3_bind_text(pStmt, 2, zUser, -1, SQLITE_STATIC); - rc = sqlite_step(pStmt); + sqlite3_bind_blob(pStmt, 1, db->auth.zAuthPW, db->auth.nAuthPW,SQLITE_STATIC); + sqlite3_bind_text(pStmt, 2, db->auth.zAuthUser, -1, SQLITE_STATIC); + rc = sqlite3_step(pStmt); if( rc==SQLITE_ROW && sqlite3_column_int(pStmt,0) ){ - *pbOk = sqlite3_column_int(pStmt, 1); + *peAuth = sqlite3_column_int(pStmt, 1) + UAUTH_User; + }else{ + *peAuth = UAUTH_Fail; } sqlite3_finalize(pStmt); return rc; } +int sqlite3UserAuthCheckLogin( + sqlite3 *db, /* The database connection to check */ + const char *zDb, /* Name of specific database to check */ + u8 *peAuth /* OUT: One of UAUTH_* constants */ +){ + int rc; + u8 savedAuthLevel; + savedAuthLevel = db->auth.authLevel; + db->auth.authLevel = UAUTH_Admin; + rc = userAuthCheckLogin(db, zDb, peAuth); + db->auth.authLevel = savedAuthLevel; + return rc; +} + /* ** If a database contains the SQLITE_USER table, then the ** sqlite3_user_authenticate() interface must be invoked with an ** appropriate username and password prior to enable read and write @@ -114,33 +130,33 @@ */ 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 *zPW /* Password or credentials */ ){ - int bOk = 0; int rc; - - rc = sqlite3UserAuthCheckLogin(db, zUsername, nPw, zPw, &bOk); - if( bOk ){ - db->auth.authFlags = bOk==2 ? UAUTH_Auth|UAUTH_Admin : UAUTH_Auth; - sqlite3_free(db->auth.zAuthUser); - db->auth.zAuthUser = sqlite3_malloc("%s", zUsername); - sqlite3_free(db->auth.zPw); - db->auth.zPw = sqlite3_malloc( nPw+1 ); - if( db->auth.zPw ){ - memcpy(db->auth.zPw,zPw,nPw); - db->auth.nPw = nPw; - rc = SQLITE_OK; - }else{ - rc = SQLITE_NOMEM; - } - }else{ - db->auth.authFlags = 0; - } - return rc; + u8 authLevel = UAUTH_Fail; + db->auth.authLevel = UAUTH_Unknown; + sqlite3_free(db->auth.zAuthUser); + sqlite3_free(db->auth.zAuthPW); + memset(&db->auth, 0, sizeof(db->auth)); + db->auth.zAuthUser = sqlite3_mprintf("%s", zUsername); + if( db->auth.zAuthUser==0 ) return SQLITE_NOMEM; + db->auth.zAuthPW = sqlite3_malloc( nPW+1 ); + if( db->auth.zAuthPW==0 ) return SQLITE_NOMEM; + memcpy(db->auth.zAuthPW,zPW,nPW); + db->auth.nAuthPW = nPW; + rc = sqlite3UserAuthCheckLogin(db, "main", &authLevel); + db->auth.authLevel = authLevel; + if( rc ){ + return rc; /* OOM error, I/O error, etc. */ + } + if( authLevelauth.authLevelauth.authLevelauth.zAuthUser, zUsername)!=0 + && db->auth.authLevelauth.authLevelauth.authLevelnDb; i++){ int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ if( zDatabase!=0 && sqlite3StrICmp(zDatabase, db->aDb[j].zName) ) continue; assert( sqlite3SchemaMutexHeld(db, j, 0) ); @@ -346,10 +348,16 @@ }else{ sqlite3ErrorMsg(pParse, "%s: %s", zMsg, zName); } pParse->checkSchema = 1; } +#if SQLITE_USER_AUTHENICATION + else if( pParse->db->auth.authLevelaDb[0].pSchema = sqlite3SchemaGet(db, db->aDb[0].pBt); db->aDb[1].pSchema = sqlite3SchemaGet(db, 0); -#if SQLITE_USER_AUTHENTICATION - db->auth.authFlags = UAUTH_Auth|UAUTH_Admin; -#endif - /* The default safety_level for the main database is 'full'; for the temp ** database it is 'NONE'. This matches the pager layer defaults. */ db->aDb[0].zName = "main"; db->aDb[0].safety_level = 3; Index: src/pragma.c ================================================================== --- src/pragma.c +++ src/pragma.c @@ -1396,11 +1396,11 @@ /* Foreign key support may not be enabled or disabled while not ** in auto-commit mode. */ mask &= ~(SQLITE_ForeignKeys); } #if SQLITE_USER_AUTHENTICATION - if( !DbIsAdmin(db) ){ + if( db->auth.authLevelaDb[iDb].zName); if( ALWAYS(pTab) ){ pTab->tabFlags |= TF_Readonly; } -#if SQLITE_USER_AUTHENTICATION - db->auth.authFlags = UAUTH_Auth|UAUTH_Admin; -#endif /* Create a cursor to hold the database open */ pDb = &db->aDb[iDb]; if( pDb->pBt==0 ){ @@ -362,18 +359,10 @@ ** even when its contents have been corrupted. */ DbSetProperty(db, iDb, DB_SchemaLoaded); rc = SQLITE_OK; } -#if SQLITE_USER_AUTHENTICATION - if( rc==SQLITE_OK && iDb!=1 ){ - if( sqlite3FindTable(db, "sqlite_user", db->aDb[iDb].zName)!=0 ){ - db->auth.authFlags = UAUTH_AuthReqd; - } - } -#endif - /* Jump here for an error that occurs after successfully allocating ** curMain and calling sqlite3BtreeEnter(). For an error that occurs ** before that point, jump to error_out. */ @@ -418,12 +407,12 @@ /* Once all the other databases have been initialized, load the schema ** for the TEMP database. This is loaded last, as the TEMP database ** schema may contain references to objects in other databases. */ #ifndef SQLITE_OMIT_TEMPDB - if( rc==SQLITE_OK && ALWAYS(db->nDb>1) - && !DbHasProperty(db, 1, DB_SchemaLoaded) ){ + assert( db->nDb>1 ); + if( rc==SQLITE_OK && !DbHasProperty(db, 1, DB_SchemaLoaded) ){ rc = sqlite3InitOne(db, 1, pzErrMsg); if( rc ){ sqlite3ResetOneSchema(db, 1); } } @@ -723,27 +712,30 @@ *ppStmt = 0; if( !sqlite3SafetyCheckOk(db) ){ return SQLITE_MISUSE_BKPT; } sqlite3_mutex_enter(db->mutex); +#if SQLITE_USER_AUTHENTICATION + if( db->auth.authLevelauth.authLevel==UAUTH_Unknown ){ + u8 authLevel = UAUTH_Fail; + sqlite3UserAuthCheckLogin(db, "main", &authLevel); + db->auth.authLevel = authLevel; + } + if( db->auth.authLevelmutex); + return SQLITE_ERROR; + } + } +#endif sqlite3BtreeEnterAll(db); rc = sqlite3Prepare(db, zSql, nBytes, saveSqlFlag, pOld, ppStmt, pzTail); if( rc==SQLITE_SCHEMA ){ sqlite3_finalize(*ppStmt); rc = sqlite3Prepare(db, zSql, nBytes, saveSqlFlag, pOld, ppStmt, pzTail); } -#if SQLITE_USER_AUTHENTICATION - assert( rc==SQLITE_OK || *ppStmt==0 ); -printf("rc=%d init=%d auth=%d sql=[%.50s]\n", rc, db->init.busy, db->auth.authFlags, zSql); -fflush(stdout); - if( rc==SQLITE_OK && !DbIsAuth(db) && db->init.busy==0 ){ - sqlite3_finalize(*ppStmt); - *ppStmt = 0; - sqlite3ErrorWithMsg(db, SQLITE_ERROR, "user not authenticated"); - rc = SQLITE_ERROR; - } -#endif sqlite3BtreeLeaveAll(db); sqlite3_mutex_leave(db->mutex); assert( rc==SQLITE_OK || *ppStmt==0 ); return rc; } Index: src/sqliteInt.h ================================================================== --- src/sqliteInt.h +++ src/sqliteInt.h @@ -993,28 +993,25 @@ ** Information held in the "sqlite3" database connection object and used ** to manage user authentication. */ typedef struct sqlite3_userauth sqlite3_userauth; struct sqlite3_userauth { - u8 authFlags; /* Status flags for user authentication */ + u8 authLevel; /* Current authentication level */ int nAuthPW; /* Size of the zAuthPW in bytes */ char *zAuthPW; /* Password used to authenticate */ char *zAuthUser; /* User name used to authenticate */ }; -/* Allowed values for sqlite3_userauth.authFlags */ -#define UAUTH_Ovrd 0x01 /* Do not enforce access restrictions */ -#define UAUTH_Auth 0x02 /* True if the user has authenticated */ -#define UAUTH_Admin 0x04 /* True if the user is an administrator */ -#define UAUTH_AuthReqd 0x08 /* True if main has an sqlite_user table */ - -/* Macros for accessing sqlite3.auth.authFlags */ -#define DbIsAuth(D) (((D)->auth.authFlags&UAUTH_Auth)!=0) -#define DbIsAdmin(D) (((D)->auth.authFlags&UAUTH_Admin)!=0) +/* Allowed values for sqlite3_userauth.authLevel */ +#define UAUTH_Unknown 0 /* Authentication not yet checked */ +#define UAUTH_Fail 1 /* User authentication failed */ +#define UAUTH_User 2 /* Authenticated as a normal user */ +#define UAUTH_Admin 3 /* Authenticated as an administrator */ /* Functions used only by user authorization logic */ int sqlite3UserAuthTable(const char*); +int sqlite3UserAuthCheckLogin(sqlite3*,const char*,u8*); #endif /* SQLITE_USER_AUTHENTICATION */ /*