diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/auth.c | 31 | ||||
-rw-r--r-- | src/build.c | 60 | ||||
-rw-r--r-- | src/copy.c | 9 | ||||
-rw-r--r-- | src/delete.c | 7 | ||||
-rw-r--r-- | src/expr.c | 19 | ||||
-rw-r--r-- | src/insert.c | 7 | ||||
-rw-r--r-- | src/pragma.c | 4 | ||||
-rw-r--r-- | src/select.c | 4 | ||||
-rw-r--r-- | src/sqlite.h.in | 9 | ||||
-rw-r--r-- | src/sqliteInt.h | 19 | ||||
-rw-r--r-- | src/tclsqlite.c | 144 | ||||
-rw-r--r-- | src/test1.c | 124 | ||||
-rw-r--r-- | src/trigger.c | 12 | ||||
-rw-r--r-- | src/update.c | 4 |
14 files changed, 258 insertions, 195 deletions
diff --git a/src/auth.c b/src/auth.c index b47e657ef..47b6600a5 100644 --- a/src/auth.c +++ b/src/auth.c @@ -14,7 +14,7 @@ ** systems that do not need this facility may omit it by recompiling ** the library with -DSQLITE_OMIT_AUTHORIZATION=1 ** -** $Id: auth.c,v 1.5 2003/04/16 20:24:52 drh Exp $ +** $Id: auth.c,v 1.6 2003/04/22 20:30:38 drh Exp $ */ #include "sqliteInt.h" @@ -52,7 +52,7 @@ */ int sqlite_set_authorizer( sqlite *db, - int (*xAuth)(void*,int,const char*,const char*), + int (*xAuth)(void*,int,const char*,const char*,const char*,const char*), void *pArg ){ db->xAuth = xAuth; @@ -94,7 +94,12 @@ void sqliteAuthRead( Table *pTab; /* The table being read */ const char *zCol; /* Name of the column of the table */ int iSrc; /* Index in pTabList->a[] of table being read */ + const char *zDBase; /* Name of database being accessed */ + const char *zTrig; /* Name of the trigger doing the accessing */ + TriggerStack *pStack; /* The stack of current triggers */ + pStack = pParse->trigStack; + zTrig = pStack ? pStack->pTrigger->name : 0; if( db->xAuth==0 ) return; assert( pExpr->op==TK_COLUMN ); iSrc = pExpr->iTable - base; @@ -104,7 +109,6 @@ void sqliteAuthRead( /* This must be an attempt to read the NEW or OLD pseudo-tables ** of a trigger. */ - TriggerStack *pStack = pParse->trigStack; assert( pStack!=0 ); assert( pExpr->iTable==pStack->newIdx || pExpr->iTable==pStack->oldIdx ); pTab = pStack->pTab; @@ -119,12 +123,19 @@ void sqliteAuthRead( }else{ zCol = "ROWID"; } - rc = db->xAuth(db->pAuthArg, SQLITE_READ, pTab->zName, zCol); + assert( pExpr->iDb>=0 && pExpr->iDb<db->nDb ); + zDBase = db->aDb[pExpr->iDb].zName; + rc = db->xAuth(db->pAuthArg, SQLITE_READ, pTab->zName, zCol, zDBase, zTrig); if( rc==SQLITE_IGNORE ){ pExpr->op = TK_NULL; }else if( rc==SQLITE_DENY ){ - sqliteSetString(&pParse->zErrMsg,"access to ", - pTab->zName, ".", zCol, " is prohibited", 0); + if( db->nDb>2 || pExpr->iDb!=0 ){ + sqliteSetString(&pParse->zErrMsg,"access to ", zDBase, ".", + pTab->zName, ".", zCol, " is prohibited", 0); + }else{ + sqliteSetString(&pParse->zErrMsg,"access to ", pTab->zName, ".", + zCol, " is prohibited", 0); + } pParse->nErr++; pParse->rc = SQLITE_AUTH; }else if( rc!=SQLITE_OK ){ @@ -142,14 +153,18 @@ int sqliteAuthCheck( Parse *pParse, int code, const char *zArg1, - const char *zArg2 + const char *zArg2, + const char *zArg3 ){ sqlite *db = pParse->db; int rc; + const char *zTrigName; + if( db->xAuth==0 ){ return SQLITE_OK; } - rc = db->xAuth(db->pAuthArg, code, zArg1, zArg2); + zTrigName = pParse->trigStack ? pParse->trigStack->pTrigger->name : 0; + rc = db->xAuth(db->pAuthArg, code, zArg1, zArg2, zArg3, zTrigName); if( rc==SQLITE_DENY ){ sqliteSetString(&pParse->zErrMsg, "not authorized", 0); pParse->rc = SQLITE_AUTH; diff --git a/src/build.c b/src/build.c index 730d78269..27cf94427 100644 --- a/src/build.c +++ b/src/build.c @@ -23,7 +23,7 @@ ** ROLLBACK ** PRAGMA ** -** $Id: build.c,v 1.148 2003/04/21 18:48:46 drh Exp $ +** $Id: build.c,v 1.149 2003/04/22 20:30:38 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -453,12 +453,13 @@ void sqliteStartTable( if( pParse->iDb==1 ) isTemp = 1; #ifndef SQLITE_OMIT_AUTHORIZATION assert( (isTemp & 1)==isTemp ); - if( sqliteAuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(isTemp), 0) ){ - sqliteFree(zName); - return; - } { int code; + char *zDb = isTemp ? "temp" : "main"; + if( sqliteAuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(isTemp), 0, zDb) ){ + sqliteFree(zName); + return; + } if( isView ){ if( isTemp ){ code = SQLITE_CREATE_TEMP_VIEW; @@ -472,7 +473,7 @@ void sqliteStartTable( code = SQLITE_CREATE_TABLE; } } - if( sqliteAuthCheck(pParse, code, zName, 0) ){ + if( sqliteAuthCheck(pParse, code, zName, 0, zDb) ){ sqliteFree(zName); return; } @@ -1218,12 +1219,15 @@ void sqliteDropTable(Parse *pParse, Token *pName, int isView){ pTable = sqliteTableFromToken(pParse, pName); if( pTable==0 ) return; iDb = pTable->iDb; + assert( iDb>=0 && iDb<db->nDb ); #ifndef SQLITE_OMIT_AUTHORIZATION - if( sqliteAuthCheck(pParse, SQLITE_DELETE, SCHEMA_TABLE(pTable->iDb),0)){ - return; - } { int code; + const char *zTab = SCHEMA_TABLE(pTable->iDb); + const char *zDb = db->aDb[pTable->iDb].zName; + if( sqliteAuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb)){ + return; + } if( isView ){ if( iDb==1 ){ code = SQLITE_DROP_TEMP_VIEW; @@ -1237,10 +1241,10 @@ void sqliteDropTable(Parse *pParse, Token *pName, int isView){ code = SQLITE_DROP_TABLE; } } - if( sqliteAuthCheck(pParse, code, pTable->zName, 0) ){ + if( sqliteAuthCheck(pParse, code, pTable->zName, 0, zDb) ){ return; } - if( sqliteAuthCheck(pParse, SQLITE_DELETE, pTable->zName, 0) ){ + if( sqliteAuthCheck(pParse, SQLITE_DELETE, pTable->zName, 0, zDb) ){ return; } } @@ -1600,15 +1604,19 @@ void sqliteCreateIndex( /* Check for authorization to create an index. */ #ifndef SQLITE_OMIT_AUTHORIZATION - assert( isTemp==0 || isTemp==1 ); - assert( pTab->iDb==pParse->iDb || isTemp==1 ); - if( sqliteAuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(isTemp), 0) ){ - goto exit_create_index; - } - i = SQLITE_CREATE_INDEX; - if( isTemp ) i = SQLITE_CREATE_TEMP_INDEX; - if( sqliteAuthCheck(pParse, i, zName, pTab->zName) ){ - goto exit_create_index; + { + const char *zDb = db->aDb[pTab->iDb].zName; + + assert( isTemp==0 || isTemp==1 ); + assert( pTab->iDb==pParse->iDb || isTemp==1 ); + if( sqliteAuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(isTemp), 0, zDb) ){ + goto exit_create_index; + } + i = SQLITE_CREATE_INDEX; + if( isTemp ) i = SQLITE_CREATE_TEMP_INDEX; + if( sqliteAuthCheck(pParse, i, zName, pTab->zName, zDb) ){ + goto exit_create_index; + } } #endif @@ -1813,11 +1821,13 @@ void sqliteDropIndex(Parse *pParse, SrcList *pName){ { int code = SQLITE_DROP_INDEX; Table *pTab = pIndex->pTable; - if( sqliteAuthCheck(pParse, SQLITE_DELETE, SCHEMA_TABLE(pIndex->iDb), 0) ){ + const char *zDb = db->aDb[pIndex->iDb].zName; + const char *zTab = SCHEMA_TABLE(pIndex->iDb); + if( sqliteAuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){ goto exit_drop_index; } if( pIndex->iDb ) code = SQLITE_DROP_TEMP_INDEX; - if( sqliteAuthCheck(pParse, code, pIndex->zName, pTab->zName) ){ + if( sqliteAuthCheck(pParse, code, pIndex->zName, pTab->zName, zDb) ){ goto exit_drop_index; } } @@ -2035,7 +2045,7 @@ void sqliteBeginTransaction(Parse *pParse, int onError){ if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return; if( pParse->nErr || sqlite_malloc_failed ) return; - if( sqliteAuthCheck(pParse, SQLITE_TRANSACTION, "BEGIN", 0) ) return; + if( sqliteAuthCheck(pParse, SQLITE_TRANSACTION, "BEGIN", 0, 0) ) return; if( db->flags & SQLITE_InTrans ){ sqliteErrorMsg(pParse, "cannot start a transaction within a transaction"); return; @@ -2053,7 +2063,7 @@ void sqliteCommitTransaction(Parse *pParse){ if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return; if( pParse->nErr || sqlite_malloc_failed ) return; - if( sqliteAuthCheck(pParse, SQLITE_TRANSACTION, "COMMIT", 0) ) return; + if( sqliteAuthCheck(pParse, SQLITE_TRANSACTION, "COMMIT", 0, 0) ) return; if( (db->flags & SQLITE_InTrans)==0 ){ sqliteErrorMsg(pParse, "cannot commit - no transaction is active"); return; @@ -2072,7 +2082,7 @@ void sqliteRollbackTransaction(Parse *pParse){ if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return; if( pParse->nErr || sqlite_malloc_failed ) return; - if( sqliteAuthCheck(pParse, SQLITE_TRANSACTION, "ROLLBACK", 0) ) return; + if( sqliteAuthCheck(pParse, SQLITE_TRANSACTION, "ROLLBACK", 0, 0) ) return; if( (db->flags & SQLITE_InTrans)==0 ){ sqliteErrorMsg(pParse, "cannot rollback - no transaction is active"); return; diff --git a/src/copy.c b/src/copy.c index 076b0a478..69711dca6 100644 --- a/src/copy.c +++ b/src/copy.c @@ -11,7 +11,7 @@ ************************************************************************* ** This file contains code used to implement the COPY command. ** -** $Id: copy.c,v 1.2 2003/04/15 19:22:23 drh Exp $ +** $Id: copy.c,v 1.3 2003/04/22 20:30:39 drh Exp $ */ #include "sqliteInt.h" @@ -39,6 +39,7 @@ void sqliteCopy( int addr, end; Index *pIdx; char *zFile = 0; + const char *zDb; sqlite *db = pParse->db; @@ -48,8 +49,10 @@ void sqliteCopy( if( pTab==0 || sqliteIsReadOnly(pParse, pTab) ) goto copy_cleanup; zFile = sqliteStrNDup(pFilename->z, pFilename->n); sqliteDequote(zFile); - if( sqliteAuthCheck(pParse, SQLITE_INSERT, pTab->zName, zFile) - || sqliteAuthCheck(pParse, SQLITE_COPY, pTab->zName, zFile) ){ + assert( pTab->iDb>=0 && pTab->iDb<db->nDb ); + zDb = db->aDb[pTab->iDb].zName; + if( sqliteAuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0, zDb) + || sqliteAuthCheck(pParse, SQLITE_COPY, pTab->zName, zFile, zDb) ){ goto copy_cleanup; } v = sqliteGetVdbe(pParse); diff --git a/src/delete.c b/src/delete.c index 9d88de4af..8899e717c 100644 --- a/src/delete.c +++ b/src/delete.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle DELETE FROM statements. ** -** $Id: delete.c,v 1.52 2003/04/17 22:57:53 drh Exp $ +** $Id: delete.c,v 1.53 2003/04/22 20:30:39 drh Exp $ */ #include "sqliteInt.h" @@ -58,6 +58,7 @@ void sqliteDeleteFrom( ){ Vdbe *v; /* The virtual database engine */ Table *pTab; /* The table from which records will be deleted */ + const char *zDb; /* Name of database holding pTab */ int end, addr; /* A couple addresses of generated code */ int i; /* Loop counter */ WhereInfo *pWInfo; /* Information about the WHERE clause */ @@ -97,7 +98,9 @@ void sqliteDeleteFrom( } if( sqliteIsReadOnly(pParse, pTab) ) goto delete_from_cleanup; assert( pTab->pSelect==0 ); /* This table is not a view */ - if( sqliteAuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0) ){ + assert( pTab->iDb<db->nDb ); + zDb = db->aDb[pTab->iDb].zName; + if( sqliteAuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb) ){ goto delete_from_cleanup; } diff --git a/src/expr.c b/src/expr.c index 059b7bbe7..90f00f3aa 100644 --- a/src/expr.c +++ b/src/expr.c @@ -12,7 +12,7 @@ ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** -** $Id: expr.c,v 1.93 2003/04/19 17:27:25 drh Exp $ +** $Id: expr.c,v 1.94 2003/04/22 20:30:39 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -432,6 +432,8 @@ int sqliteExprResolveIds( int cnt = 0; /* Number of matches */ int i; /* Loop counter */ char *z; + int iDb = -1; + assert( pExpr->token.z ); z = sqliteStrNDup(pExpr->token.z, pExpr->token.n); sqliteDequote(z); @@ -440,11 +442,13 @@ int sqliteExprResolveIds( int j; Table *pTab = pTabList->a[i].pTab; if( pTab==0 ) continue; + iDb = pTab->iDb; assert( pTab->nCol>0 ); for(j=0; j<pTab->nCol; j++){ if( sqliteStrICmp(pTab->aCol[j].zName, z)==0 ){ cnt++; pExpr->iTable = i + base; + pExpr->iDb = pTab->iDb; if( j==pTab->iPKey ){ /* Substitute the record number for the INTEGER PRIMARY KEY */ pExpr->iColumn = -1; @@ -470,9 +474,10 @@ int sqliteExprResolveIds( } } } - if( cnt==0 && sqliteIsRowid(z) ){ + if( cnt==0 && iDb>=0 && sqliteIsRowid(z) ){ pExpr->iColumn = -1; pExpr->iTable = base; + pExpr->iDb = iDb; cnt = 1 + (pTabList->nSrc>1); pExpr->op = TK_COLUMN; pExpr->dataType = SQLITE_SO_NUM; @@ -544,11 +549,15 @@ int sqliteExprResolveIds( continue; } } - if( 0==(cntTab++) ) pExpr->iTable = i + base; + if( 0==(cntTab++) ){ + pExpr->iTable = i + base; + pExpr->iDb = pTab->iDb; + } for(j=0; j<pTab->nCol; j++){ if( sqliteStrICmp(pTab->aCol[j].zName, zRight)==0 ){ cnt++; pExpr->iTable = i + base; + pExpr->iDb = pTab->iDb; /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */ pExpr->iColumn = j==pTab->iPKey ? -1 : j; pExpr->dataType = pTab->aCol[j].sortOrder & SQLITE_SO_TYPEMASK; @@ -563,11 +572,15 @@ int sqliteExprResolveIds( int t = 0; if( pTriggerStack->newIdx != -1 && sqliteStrICmp("new", zLeft) == 0 ){ pExpr->iTable = pTriggerStack->newIdx; + assert( pTriggerStack->pTab ); + pExpr->iDb = pTriggerStack->pTab->iDb; cntTab++; t = 1; } if( pTriggerStack->oldIdx != -1 && sqliteStrICmp("old", zLeft) == 0 ){ pExpr->iTable = pTriggerStack->oldIdx; + assert( pTriggerStack->pTab ); + pExpr->iDb = pTriggerStack->pTab->iDb; cntTab++; t = 1; } diff --git a/src/insert.c b/src/insert.c index f7773314c..940536f56 100644 --- a/src/insert.c +++ b/src/insert.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle INSERT statements in SQLite. ** -** $Id: insert.c,v 1.80 2003/04/20 17:29:24 drh Exp $ +** $Id: insert.c,v 1.81 2003/04/22 20:30:39 drh Exp $ */ #include "sqliteInt.h" @@ -93,6 +93,7 @@ void sqliteInsert( ){ Table *pTab; /* The table to insert into */ char *zTab; /* Name of the table into which we are inserting */ + const char *zDb; /* Name of the database holding this table */ int i, j, idx; /* Loop counters */ Vdbe *v; /* Generate code into this virtual machine */ Index *pIdx; /* For looping over indices of the table */ @@ -126,7 +127,9 @@ void sqliteInsert( if( pTab==0 ){ goto insert_cleanup; } - if( sqliteAuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0) ){ + assert( pTab->iDb<db->nDb ); + zDb = db->aDb[pTab->iDb].zName; + if( sqliteAuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0, zDb) ){ goto insert_cleanup; } diff --git a/src/pragma.c b/src/pragma.c index 1466cc1b6..6b2604844 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -11,7 +11,7 @@ ************************************************************************* ** This file contains code used to implement the PRAGMA command. ** -** $Id: pragma.c,v 1.3 2003/04/15 01:19:49 drh Exp $ +** $Id: pragma.c,v 1.4 2003/04/22 20:30:39 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -107,7 +107,7 @@ void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){ zRight = sqliteStrNDup(pRight->z, pRight->n); sqliteDequote(zRight); } - if( sqliteAuthCheck(pParse, SQLITE_PRAGMA, zLeft, zRight) ){ + if( sqliteAuthCheck(pParse, SQLITE_PRAGMA, zLeft, zRight, 0) ){ sqliteFree(zLeft); sqliteFree(zRight); return; diff --git a/src/select.c b/src/select.c index 3aef002cc..f311fa765 100644 --- a/src/select.c +++ b/src/select.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** -** $Id: select.c,v 1.132 2003/04/17 22:57:54 drh Exp $ +** $Id: select.c,v 1.133 2003/04/22 20:30:39 drh Exp $ */ #include "sqliteInt.h" @@ -1917,7 +1917,7 @@ int sqliteSelect( int rc = 1; /* Value to return from this function */ if( sqlite_malloc_failed || pParse->nErr || p==0 ) return 1; - if( sqliteAuthCheck(pParse, SQLITE_SELECT, 0, 0) ) return 1; + if( sqliteAuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1; /* If there is are a sequence of queries, do the earlier ones first. */ diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 7d9e12b8c..377b9f542 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -12,7 +12,7 @@ ** This header file defines the interface that the SQLite library ** presents to client programs. ** -** @(#) $Id: sqlite.h.in,v 1.44 2003/04/03 15:46:04 drh Exp $ +** @(#) $Id: sqlite.h.in,v 1.45 2003/04/22 20:30:39 drh Exp $ */ #ifndef _SQLITE_H_ #define _SQLITE_H_ @@ -513,7 +513,7 @@ int sqlite_aggregate_count(sqlite_func*); */ int sqlite_set_authorizer( sqlite*, - int (*xAuth)(void*,int,const char*,const char*), + int (*xAuth)(void*,int,const char*,const char*,const char*,const char*), void *pUserData ); @@ -522,7 +522,10 @@ int sqlite_set_authorizer( ** be one of the values below. These values signify what kind of operation ** is to be authorized. The 3rd and 4th parameters to the authorization ** function will be parameters or NULL depending on which of the following -** codes is used as the second parameter. +** codes is used as the second parameter. The 5th parameter is the name +** of the database ("main", "temp", etc.) if applicable. The 6th parameter +** is the name of the trigger that is responsible for the access attempt, +** or NULL if this access attempt is directly from input SQL code. ** ** Arg-3 Arg-4 */ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 135523ada..c95a56710 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.177 2003/04/21 18:48:47 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.178 2003/04/22 20:30:39 drh Exp $ */ #include "config.h" #include "sqlite.h" @@ -105,6 +105,9 @@ #ifndef UINT8_TYPE # define UINT8_TYPE unsigned char #endif +#ifndef INT8_TYPE +# define INT8_TYPE signed char +#endif #ifndef INTPTR_TYPE # if SQLITE_PTR_SZ==4 # define INTPTR_TYPE int @@ -115,6 +118,7 @@ typedef UINT32_TYPE u32; /* 4-byte unsigned integer */ typedef UINT16_TYPE u16; /* 2-byte unsigned integer */ typedef UINT8_TYPE u8; /* 1-byte unsigned integer */ +typedef INT8_TYPE i8; /* 1-byte signed integer */ typedef INTPTR_TYPE ptr; /* Big enough to hold a pointer */ typedef unsigned INTPTR_TYPE uptr; /* Big enough to hold a pointer */ @@ -290,7 +294,8 @@ struct sqlite { void *pTraceArg; /* Argument to the trace function */ #endif #ifndef SQLITE_OMIT_AUTHORIZATION - int (*xAuth)(void*,int,const char*,const char*); /* Access Auth function */ + int (*xAuth)(void*,int,const char*,const char*,const char*,const char*); + /* Access authorization function */ void *pAuthArg; /* 1st argument to the access auth function */ #endif }; @@ -580,7 +585,8 @@ struct Token { struct Expr { u8 op; /* Operation performed by this node */ u8 dataType; /* Either SQLITE_SO_TEXT or SQLITE_SO_NUM */ - u16 flags; /* Various flags. See below */ + i8 iDb; /* Database referenced by this expression */ + u8 flags; /* Various flags. See below */ Expr *pLeft, *pRight; /* Left and right subnodes */ ExprList *pList; /* A list of expressions used as function arguments ** or in "<expr> IN (<expr-list)" */ @@ -953,9 +959,8 @@ struct TriggerStack { int oldIdx; /* Index of vdbe cursor to "old" temp table */ int orconf; /* Current orconf policy */ int ignoreJump; /* where to jump to for a RAISE(IGNORE) */ - Trigger *pTrigger; - - TriggerStack *pNext; + Trigger *pTrigger; /* The trigger currently being coded */ + TriggerStack *pNext; /* Next trigger down on the trigger stack */ }; /* @@ -1113,7 +1118,7 @@ void sqliteCreateForeignKey(Parse*, IdList*, Token*, IdList*, int); void sqliteDeferForeignKey(Parse*, int); #ifndef SQLITE_OMIT_AUTHORIZATION void sqliteAuthRead(Parse*,Expr*,SrcList*,int); - int sqliteAuthCheck(Parse*,int, const char*, const char*); + int sqliteAuthCheck(Parse*,int, const char*, const char*, const char*); #else # define sqliteAuthRead(a,b,c,d) # define sqliteAuthCheck(a,b,c,d) SQLITE_OK diff --git a/src/tclsqlite.c b/src/tclsqlite.c index dd21cad4e..b1b446f98 100644 --- a/src/tclsqlite.c +++ b/src/tclsqlite.c @@ -11,7 +11,7 @@ ************************************************************************* ** A TCL Interface to SQLite ** -** $Id: tclsqlite.c,v 1.46 2003/04/03 15:46:04 drh Exp $ +** $Id: tclsqlite.c,v 1.47 2003/04/22 20:30:39 drh Exp $ */ #ifndef NO_TCL /* Omit this whole file if TCL is unavailable */ @@ -53,6 +53,7 @@ struct SqliteDb { char *zBusy; /* The busy callback routine */ char *zBegin; /* The begin-transaction callback routine */ char *zCommit; /* The commit-transaction callback routine */ + char *zAuth; /* The authorization callback routine */ SqlFunc *pFunc; /* List of SQL functions */ int rc; /* Return code of most recent sqlite_exec() */ }; @@ -268,6 +269,9 @@ static void DbDeleteCmd(void *db){ if( pDb->zCommit ){ Tcl_Free(pDb->zCommit); } + if( pDb->zAuth ){ + Tcl_Free(pDb->zAuth); + } Tcl_Free((char*)pDb); } @@ -351,6 +355,76 @@ static void tclSqlFunc(sqlite_func *context, int argc, const char **argv){ sqlite_set_result_string(context, Tcl_GetStringResult(p->interp), -1); } } +#ifndef SQLITE_OMIT_AUTHORIZATION +/* +** This is the authentication function. It appends the authentication +** type code and the two arguments to zCmd[] then invokes the result +** on the interpreter. The reply is examined to determine if the +** authentication fails or succeeds. +*/ +static int auth_callback( + void *pArg, + int code, + const char *zArg1, + const char *zArg2, + const char *zArg3, + const char *zArg4 +){ + char *zCode; + Tcl_DString str; + int rc; + const char *zReply; + SqliteDb *pDb = (SqliteDb*)pArg; + + switch( code ){ + case SQLITE_COPY : zCode="SQLITE_COPY"; break; + case SQLITE_CREATE_INDEX : zCode="SQLITE_CREATE_INDEX"; break; + case SQLITE_CREATE_TABLE : zCode="SQLITE_CREATE_TABLE"; break; + case SQLITE_CREATE_TEMP_INDEX : zCode="SQLITE_CREATE_TEMP_INDEX"; break; + case SQLITE_CREATE_TEMP_TABLE : zCode="SQLITE_CREATE_TEMP_TABLE"; break; + case SQLITE_CREATE_TEMP_TRIGGER: zCode="SQLITE_CREATE_TEMP_TRIGGER"; break; + case SQLITE_CREATE_TEMP_VIEW : zCode="SQLITE_CREATE_TEMP_VIEW"; break; + case SQLITE_CREATE_TRIGGER : zCode="SQLITE_CREATE_TRIGGER"; break; + case SQLITE_CREATE_VIEW : zCode="SQLITE_CREATE_VIEW"; break; + case SQLITE_DELETE : zCode="SQLITE_DELETE"; break; + case SQLITE_DROP_INDEX : zCode="SQLITE_DROP_INDEX"; break; + case SQLITE_DROP_TABLE : zCode="SQLITE_DROP_TABLE"; break; + case SQLITE_DROP_TEMP_INDEX : zCode="SQLITE_DROP_TEMP_INDEX"; break; + case SQLITE_DROP_TEMP_TABLE : zCode="SQLITE_DROP_TEMP_TABLE"; break; + case SQLITE_DROP_TEMP_TRIGGER : zCode="SQLITE_DROP_TEMP_TRIGGER"; break; + case SQLITE_DROP_TEMP_VIEW : zCode="SQLITE_DROP_TEMP_VIEW"; break; + case SQLITE_DROP_TRIGGER : zCode="SQLITE_DROP_TRIGGER"; break; + case SQLITE_DROP_VIEW : zCode="SQLITE_DROP_VIEW"; break; + case SQLITE_INSERT : zCode="SQLITE_INSERT"; break; + case SQLITE_PRAGMA : zCode="SQLITE_PRAGMA"; break; + case SQLITE_READ : zCode="SQLITE_READ"; break; + case SQLITE_SELECT : zCode="SQLITE_SELECT"; break; + case SQLITE_TRANSACTION : zCode="SQLITE_TRANSACTION"; break; + case SQLITE_UPDATE : zCode="SQLITE_UPDATE"; break; + default : zCode="????"; break; + } + Tcl_DStringInit(&str); + Tcl_DStringAppend(&str, pDb->zAuth, -1); + Tcl_DStringAppendElement(&str, zCode); + Tcl_DStringAppendElement(&str, zArg1 ? zArg1 : ""); + Tcl_DStringAppendElement(&str, zArg2 ? zArg2 : ""); + Tcl_DStringAppendElement(&str, zArg3 ? zArg3 : ""); + Tcl_DStringAppendElement(&str, zArg4 ? zArg4 : ""); + rc = Tcl_GlobalEval(pDb->interp, Tcl_DStringValue(&str)); + Tcl_DStringFree(&str); + zReply = Tcl_GetStringResult(pDb->interp); + if( strcmp(zReply,"SQLITE_OK")==0 ){ + rc = SQLITE_OK; + }else if( strcmp(zReply,"SQLITE_DENY")==0 ){ + rc = SQLITE_DENY; + }else if( strcmp(zReply,"SQLITE_IGNORE")==0 ){ + rc = SQLITE_IGNORE; + }else{ + rc = 999; + } + return rc; +} +#endif /* SQLITE_OMIT_AUTHORIZATION */ /* ** The "sqlite" command below creates a new Tcl command for each @@ -369,16 +443,17 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ SqliteDb *pDb = (SqliteDb*)cd; int choice; static const char *DB_strs[] = { - "begin_hook", "busy", "changes", - "close", "commit_hook", "complete", - "errorcode", "eval", "function", - "last_insert_rowid", "timeout", 0 + "authorizer", "begin_hook", "busy", + "changes", "close", "commit_hook", + "complete", "errorcode", "eval", + "function", "last_insert_rowid", "timeout", + 0 }; enum DB_enum { - DB_BEGIN_HOOK, DB_BUSY, DB_CHANGES, - DB_CLOSE, DB_COMMIT_HOOK, DB_COMPLETE, - DB_ERRORCODE, DB_EVAL, DB_FUNCTION, - DB_LAST_INSERT_ROWID, DB_TIMEOUT, + DB_AUTHORIZER, DB_BEGIN_HOOK, DB_BUSY, + DB_CHANGES, DB_CLOSE, DB_COMMIT_HOOK, + DB_COMPLETE, DB_ERRORCODE, DB_EVAL, + DB_FUNCTION, DB_LAST_INSERT_ROWID,DB_TIMEOUT, }; if( objc<2 ){ @@ -391,6 +466,57 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ switch( (enum DB_enum)choice ){ + /* $db authorizer ?CALLBACK? + ** + ** Invoke the given callback to authorize each SQL operation as it is + ** compiled. 5 arguments are appended to the callback before it is + ** invoked: + ** + ** (1) The authorization type (ex: SQLITE_CREATE_TABLE, SQLITE_INSERT, ...) + ** (2) First descriptive name (depends on authorization type) + ** (3) Second descriptive name + ** (4) Name of the database (ex: "main", "temp") + ** (5) Name of trigger that is doing the access + ** + ** The callback should return on of the following strings: SQLITE_OK, + ** SQLITE_IGNORE, or SQLITE_DENY. Any other return value is an error. + ** + ** If this method is invoked with no arguments, the current authorization + ** callback string is returned. + */ + case DB_AUTHORIZER: { + if( objc>3 ){ + Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?"); + }else if( objc==2 ){ + if( pDb->zBegin ){ + Tcl_AppendResult(interp, pDb->zAuth, 0); + } + }else{ + char *zAuth; + int len; + if( pDb->zAuth ){ + Tcl_Free(pDb->zAuth); + } + zAuth = Tcl_GetStringFromObj(objv[2], &len); + if( zAuth && len>0 ){ + pDb->zAuth = Tcl_Alloc( len + 1 ); + strcpy(pDb->zAuth, zAuth); + }else{ + pDb->zAuth = 0; + } +#ifndef SQLITE_OMIT_AUTHORIZATION + if( pDb->zAuth ){ + pDb->interp = interp; + sqlite_set_authorizer(pDb->db, auth_callback, pDb); + }else{ + sqlite_set_authorizer(pDb->db, 0, 0); + } +#endif + } + break; + } + + /* $db begin_callback ?CALLBACK? ** ** Invoke the given callback at the beginning of every SQL transaction. diff --git a/src/test1.c b/src/test1.c index 402b2c222..92ce28cd6 100644 --- a/src/test1.c +++ b/src/test1.c @@ -13,7 +13,7 @@ ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** -** $Id: test1.c,v 1.22 2003/02/16 22:21:32 drh Exp $ +** $Id: test1.c,v 1.23 2003/04/22 20:30:40 drh Exp $ */ #include "sqliteInt.h" #include "tcl.h" @@ -588,125 +588,6 @@ static int sqlite_datatypes( return TCL_OK; } -#ifndef SQLITE_OMIT_AUTHORIZATION -/* -** Information used by the authentication function. -*/ -typedef struct AuthInfo AuthInfo; -struct AuthInfo { - Tcl_Interp *interp; /* Interpreter to use */ - int nCmd; /* Number of characters in zCmd[] */ - char zCmd[500]; /* Command to invoke */ -}; - -/* -** We create a single static authenticator. This won't work in a -** multi-threaded environment, but the test fixture is not multithreaded. -** And be making it static, we don't have to worry about deallocating -** after a test in order to void memory leaks. -*/ -static AuthInfo authInfo; - -/* -** This is the authentication function. It appends the authentication -** type code and the two arguments to zCmd[] then invokes the result -** on the interpreter. The reply is examined to determine if the -** authentication fails or succeeds. -*/ -static int auth_callback( - void *NotUsed, - int code, - const char *zArg1, - const char *zArg2 -){ - char *zCode; - Tcl_DString str; - int rc; - const char *zReply; - switch( code ){ - case SQLITE_COPY : zCode="SQLITE_COPY"; break; - case SQLITE_CREATE_INDEX : zCode="SQLITE_CREATE_INDEX"; break; - case SQLITE_CREATE_TABLE : zCode="SQLITE_CREATE_TABLE"; break; - case SQLITE_CREATE_TEMP_INDEX : zCode="SQLITE_CREATE_TEMP_INDEX"; break; - case SQLITE_CREATE_TEMP_TABLE : zCode="SQLITE_CREATE_TEMP_TABLE"; break; - case SQLITE_CREATE_TEMP_TRIGGER: zCode="SQLITE_CREATE_TEMP_TRIGGER"; break; - case SQLITE_CREATE_TEMP_VIEW : zCode="SQLITE_CREATE_TEMP_VIEW"; break; - case SQLITE_CREATE_TRIGGER : zCode="SQLITE_CREATE_TRIGGER"; break; - case SQLITE_CREATE_VIEW : zCode="SQLITE_CREATE_VIEW"; break; - case SQLITE_DELETE : zCode="SQLITE_DELETE"; break; - case SQLITE_DROP_INDEX : zCode="SQLITE_DROP_INDEX"; break; - case SQLITE_DROP_TABLE : zCode="SQLITE_DROP_TABLE"; break; - case SQLITE_DROP_TEMP_INDEX : zCode="SQLITE_DROP_TEMP_INDEX"; break; - case SQLITE_DROP_TEMP_TABLE : zCode="SQLITE_DROP_TEMP_TABLE"; break; - case SQLITE_DROP_TEMP_TRIGGER : zCode="SQLITE_DROP_TEMP_TRIGGER"; break; - case SQLITE_DROP_TEMP_VIEW : zCode="SQLITE_DROP_TEMP_VIEW"; break; - case SQLITE_DROP_TRIGGER : zCode="SQLITE_DROP_TRIGGER"; break; - case SQLITE_DROP_VIEW : zCode="SQLITE_DROP_VIEW"; break; - case SQLITE_INSERT : zCode="SQLITE_INSERT"; break; - case SQLITE_PRAGMA : zCode="SQLITE_PRAGMA"; break; - case SQLITE_READ : zCode="SQLITE_READ"; break; - case SQLITE_SELECT : zCode="SQLITE_SELECT"; break; - case SQLITE_TRANSACTION : zCode="SQLITE_TRANSACTION"; break; - case SQLITE_UPDATE : zCode="SQLITE_UPDATE"; break; - default : zCode="????"; break; - } - Tcl_DStringInit(&str); - Tcl_DStringAppend(&str, authInfo.zCmd, -1); - Tcl_DStringAppendElement(&str, zCode); - Tcl_DStringAppendElement(&str, zArg1 ? zArg1 : ""); - Tcl_DStringAppendElement(&str, zArg2 ? zArg2 : ""); - rc = Tcl_GlobalEval(authInfo.interp, Tcl_DStringValue(&str)); - Tcl_DStringFree(&str); - zReply = Tcl_GetStringResult(authInfo.interp); - if( strcmp(zReply,"SQLITE_OK")==0 ){ - rc = SQLITE_OK; - }else if( strcmp(zReply,"SQLITE_DENY")==0 ){ - rc = SQLITE_DENY; - }else if( strcmp(zReply,"SQLITE_IGNORE")==0 ){ - rc = SQLITE_IGNORE; - }else{ - rc = 999; - } - return rc; -} - -/* -** This routine creates a new authenticator. It fills in the zCmd[] -** field of the authentication function state variable and then registers -** the authentication function with the SQLite library. -*/ -static int test_set_authorizer( - void *NotUsed, - Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ - int argc, /* Number of arguments */ - char **argv /* Text of each argument */ -){ - sqlite *db; - char *zCmd; - if( argc!=3 ){ - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " DB CALLBACK\"", 0); - return TCL_ERROR; - } - if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; - zCmd = argv[2]; - if( zCmd[0]==0 ){ - sqlite_set_authorizer(db, 0, 0); - return TCL_OK; - } - if( strlen(zCmd)>sizeof(authInfo.zCmd) ){ - Tcl_AppendResult(interp, "command too big", 0); - return TCL_ERROR; - } - authInfo.interp = interp; - authInfo.nCmd = strlen(zCmd); - strcpy(authInfo.zCmd, zCmd); - sqlite_set_authorizer(db, auth_callback, 0); - return TCL_OK; -} -#endif /* SQLITE_OMIT_AUTHORIZATION */ - - /* ** Usage: sqlite_compile DB SQL TAILVAR ** @@ -878,9 +759,6 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ { "sqlite_register_test_function", (Tcl_CmdProc*)test_register_func }, { "sqlite_abort", (Tcl_CmdProc*)sqlite_abort }, { "sqlite_datatypes", (Tcl_CmdProc*)sqlite_datatypes }, -#ifndef SQLITE_OMIT_AUTHORIZATION - { "sqlite_set_authorizer", (Tcl_CmdProc*)test_set_authorizer }, -#endif #ifdef MEMORY_DEBUG { "sqlite_malloc_fail", (Tcl_CmdProc*)sqlite_malloc_fail }, { "sqlite_malloc_stat", (Tcl_CmdProc*)sqlite_malloc_stat }, diff --git a/src/trigger.c b/src/trigger.c index 7124add96..a2fc91f51 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -98,11 +98,13 @@ void sqliteBeginTrigger( #ifndef SQLITE_OMIT_AUTHORIZATION { int code = SQLITE_CREATE_TRIGGER; + const char *zDb = db->aDb[tab->iDb].zName; + const char *zDbTrig = isTemp ? db->aDb[1].zName : zDb; if( tab->iDb==1 || isTemp ) code = SQLITE_CREATE_TEMP_TRIGGER; - if( sqliteAuthCheck(pParse, code, zName, tab->zName) ){ + if( sqliteAuthCheck(pParse, code, zName, tab->zName, zDbTrig) ){ goto trigger_cleanup; } - if( sqliteAuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(tab->iDb), 0)){ + if( sqliteAuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(tab->iDb), 0, zDb)){ goto trigger_cleanup; } } @@ -397,9 +399,11 @@ void sqliteDropTrigger(Parse *pParse, SrcList *pName, int nested){ #ifndef SQLITE_OMIT_AUTHORIZATION { int code = SQLITE_DROP_TRIGGER; + const char *zDb = db->aDb[pTrigger->iDb].zName; + const char *zTab = SCHEMA_TABLE(pTrigger->iDb); if( pTrigger->iDb ) code = SQLITE_DROP_TEMP_TRIGGER; - if( sqliteAuthCheck(pParse, code, pTrigger->name, pTable->zName) || - sqliteAuthCheck(pParse, SQLITE_DELETE, SCHEMA_TABLE(pTrigger->iDb),0) ){ + if( sqliteAuthCheck(pParse, code, pTrigger->name, pTable->zName, zDb) || + sqliteAuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){ goto drop_trigger_cleanup; } } diff --git a/src/update.c b/src/update.c index b77e1bb0c..d320033f6 100644 --- a/src/update.c +++ b/src/update.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle UPDATE statements. ** -** $Id: update.c,v 1.61 2003/04/20 17:29:24 drh Exp $ +** $Id: update.c,v 1.62 2003/04/22 20:30:40 drh Exp $ */ #include "sqliteInt.h" @@ -139,7 +139,7 @@ void sqliteUpdate( { int rc; rc = sqliteAuthCheck(pParse, SQLITE_UPDATE, pTab->zName, - pTab->aCol[j].zName); + pTab->aCol[j].zName, db->aDb[pTab->iDb].zName); if( rc==SQLITE_DENY ){ goto update_cleanup; }else if( rc==SQLITE_IGNORE ){ |