From 85e2096fb60de90ff32830cf7b9a4689370d723e Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 25 Apr 2003 17:52:11 +0000 Subject: [PATCH] Report the correct authorization context in the authorization callback when coding an INSTEAD OF trigger on an update or delete. (CVS 936) FossilOrigin-Name: 67746833fc8de3afff80db413bd63a362bb28218 --- manifest | 22 +++++++-------- manifest.uuid | 2 +- src/auth.c | 30 ++++++++++++++++++++- src/delete.c | 11 +++++++- src/sqliteInt.h | 16 ++++++++++- src/trigger.c | 7 +++-- src/update.c | 44 ++++++++++++++++++++---------- test/auth.test | 71 ++++++++++++++++++++++++++++++++++++++++++++++++- 8 files changed, 169 insertions(+), 34 deletions(-) diff --git a/manifest b/manifest index 137279ac8c..59b527de1f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\stests\sto\sinsure\sVACUUM\sworks\sin\sthe\spresence\sof\sI/O\serrors.\s\sFix\ssome\nproblems\sthat\scame\sto\slight\sby\sthese\stests.\s(CVS\s935) -D 2003-04-25T15:37:58 +C Report\sthe\scorrect\sauthorization\scontext\sin\sthe\sauthorization\scallback\nwhen\scoding\san\sINSTEAD\sOF\strigger\son\san\supdate\sor\sdelete.\s(CVS\s936) +D 2003-04-25T17:52:11 F Makefile.in 004acec253ecdde985c8ecd5b7c9accdb210378f F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd @@ -20,13 +20,13 @@ F spec.template 238f7db425a78dc1bb7682e56e3834c7270a3f5e F sqlite.1 83f4a9d37bdf2b7ef079a82d54eaf2e3509ee6ea F sqlite.pc.in 30552343140c53304c2a658c080fbe810cd09ca2 F src/attach.c 7ebc7487de43e357a64226f8abef81f2669f2183 -F src/auth.c a4afd27964fb9f661147115790c8ae2ee230ebcc +F src/auth.c 3be3c7434592117f049703966b940e0b07088ae2 F src/btree.c 077d75aee4ed63f3628698611ba43c87097d458d F src/btree.h 23c50e00709de16a5dce1fcea9c0429cc955ff0e F src/btree_rb.c 8e00e40be264716e1929987878672e55d9e0e76d F src/build.c d5a26baeffa5bc49b4b7009a7723c6ab7e1b02d9 F src/copy.c 44b13fd4d2444fb53bff8a5ecee1c5f6f86a8263 -F src/delete.c 23d33fd8967c6cc492943bbecea93be6491edc6a +F src/delete.c 0f7c26aaebc417ad66a2a1099e59cc4056512c31 F src/encode.c faf03741efe921755ec371cf4a6984536de00042 F src/expr.c 46e2bb93abd6c70e67c8cdc5d92fdcd0b95498f3 F src/func.c 882c3ed5a02be18cd904715c7ec62947a34a3605 @@ -47,7 +47,7 @@ F src/select.c dfc13cb62ba658c4463179713c40ee25a062b2ba F src/shell.c e0b3da1f44a2cc72daf41a4559b1c5f0545944a5 F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e F src/sqlite.h.in eec06462cba262c0ee03f38462a18a4bc66dda4e -F src/sqliteInt.h 5d15d1dea3f0c497a78c6a123eec5b4b92811c1c +F src/sqliteInt.h 0c7474068c37a5aad715810c8190266edcbd4f4c F src/table.c eed2098c9b577aa17f8abe89313a9c4413f57d63 F src/tclsqlite.c 9e25f98f1765afa0716144ef57abda75c88f688d F src/test1.c 4484806861a3099670188a09e12f858ec65aa56c @@ -55,8 +55,8 @@ F src/test2.c 5014337d8576b731cce5b5a14bec4f0daf432700 F src/test3.c 30985ebdfaf3ee1462a9b0652d3efbdc8d9798f5 F src/threadtest.c d641a5219e718e18a1a80a50eb9bb549f451f42e F src/tokenize.c 067d1a477a94af7712ca74e09aaa6bd0f7299527 -F src/trigger.c e763f4015c96e06b694184ead5754985c1dfdae0 -F src/update.c b7fa7c427b74aee6db56ecfa09e5e151e6f9fa6a +F src/trigger.c 62d1e1b837a98f1fa7511c77977d51c8516ddb65 +F src/update.c f40376ed2e092a7040c6fc6fa0add59fad5c5e76 F src/util.c 87635cfdfffa056a8d3147719357aa442374f78c F src/vacuum.c 14ac3073203fa021e01ffe33db56968ad79a8344 F src/vdbe.c 48098080d2b5d35d4cc28ac2a4855c7730f6ee7b @@ -64,7 +64,7 @@ F src/vdbe.h 985c24f312d10f9ef8f9a8b8ea62fcdf68e82f21 F src/where.c f632cd30f013163484a4d60c249d36fe31f5be12 F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242 F test/attach.test b311c83e370e6b22b79a8279317039440ce64862 -F test/auth.test d25a76f21494b61483787caa7b28c713bc7c7c7f +F test/auth.test dee78be1f4f920bd6b15c4c947ce4d01bfe2826d F test/bigfile.test 1cd8256d4619c39bea48147d344f348823e78678 F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578 F test/btree.test 1e3463c7838e7e71bbf37c9c6e45beee9c8975ba @@ -165,7 +165,7 @@ F www/speed.tcl cb4c10a722614aea76d2c51f32ee43400d5951be F www/sqlite.tcl ae3dcfb077e53833b59d4fcc94d8a12c50a44098 F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331 F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218 -P c3b1f84dfce13b2523c9923e4270577862ca0595 -R 40330553c4eb619fb11602a7f62ead1c +P 8d3e879349fc9523c72cb46111e0058b57ce9341 +R fbd9cacc0c39e890456b02e579584ea3 U drh -Z 09a1f9c6aa9e8c12d787618e6052f340 +Z d170dde2366e1aeda159869f0f0e19bb diff --git a/manifest.uuid b/manifest.uuid index 0e2dd63f42..977ffff6c9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8d3e879349fc9523c72cb46111e0058b57ce9341 \ No newline at end of file +67746833fc8de3afff80db413bd63a362bb28218 \ No newline at end of file diff --git a/src/auth.c b/src/auth.c index 4703ba0132..2a5a8f5648 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.7 2003/04/24 01:45:04 drh Exp $ +** $Id: auth.c,v 1.8 2003/04/25 17:52:11 drh Exp $ */ #include "sqliteInt.h" @@ -173,4 +173,32 @@ int sqliteAuthCheck( return rc; } +/* +** Push an authorization context. After this routine is called, the +** zArg3 argument to authorization callbacks will be zContext until +** popped. Or if pParse==0, this routine is a no-op. +*/ +void sqliteAuthContextPush( + Parse *pParse, + AuthContext *pContext, + const char *zContext +){ + pContext->pParse = pParse; + if( pParse ){ + pContext->zAuthContext = pParse->zAuthContext; + pParse->zAuthContext = zContext; + } +} + +/* +** Pop an authorization context that was previously pushed +** by sqliteAuthContextPush +*/ +void sqliteAuthContextPop(AuthContext *pContext){ + if( pContext->pParse ){ + pContext->pParse->zAuthContext = pContext->zAuthContext; + pContext->pParse = 0; + } +} + #endif /* SQLITE_OMIT_AUTHORIZATION */ diff --git a/src/delete.c b/src/delete.c index 7d0003578e..14c7a20e16 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.54 2003/04/24 01:45:04 drh Exp $ +** $Id: delete.c,v 1.55 2003/04/25 17:52:11 drh Exp $ */ #include "sqliteInt.h" @@ -68,12 +68,14 @@ void sqliteDeleteFrom( int base; /* Index of the first available table cursor */ sqlite *db; /* Main database structure */ int isView; /* True if attempting to delete from a view */ + AuthContext sContext; /* Authorization context */ int row_triggers_exist = 0; /* True if any triggers exist */ int before_triggers; /* True if there are BEFORE triggers */ int after_triggers; /* True if there are AFTER triggers */ int oldIdx = -1; /* Cursor for the OLD table of AFTER triggers */ + sContext.pParse = 0; if( pParse->nErr || sqlite_malloc_failed ){ pTabList = 0; goto delete_from_cleanup; @@ -127,6 +129,12 @@ void sqliteDeleteFrom( } } + /* Start the view context + */ + if( isView ){ + sqliteAuthContextPush(pParse, &sContext, pTab->zName); + } + /* Begin generating code. */ v = sqliteGetVdbe(pParse); @@ -303,6 +311,7 @@ void sqliteDeleteFrom( } delete_from_cleanup: + sqliteAuthContextPop(&sContext); sqliteSrcListDelete(pTabList); sqliteExprDelete(pWhere); return; diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 7027b30a96..c68ccd94c0 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.180 2003/04/24 01:45:04 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.181 2003/04/25 17:52:11 drh Exp $ */ #include "config.h" #include "sqlite.h" @@ -219,6 +219,7 @@ typedef struct TriggerStep TriggerStep; typedef struct TriggerStack TriggerStack; typedef struct FKey FKey; typedef struct Db Db; +typedef struct AuthContext AuthContext; /* ** Each database file to be accessed by the system is an instance @@ -834,6 +835,15 @@ struct Parse { TriggerStack *trigStack; /* Trigger actions being coded */ }; +/* +** An instance of the following structure can be declared on a stack and used +** to save the Parse.zAuthContext value so that it can be restored later. +*/ +struct AuthContext { + const char *zAuthContext; /* Put saved Parse.zAuthContext here */ + Parse *pParse; /* The Parse structure */ +}; + /* * Each trigger present in the database schema is stored as an instance of * struct Trigger. @@ -1111,9 +1121,13 @@ void sqliteDeferForeignKey(Parse*, int); #ifndef SQLITE_OMIT_AUTHORIZATION void sqliteAuthRead(Parse*,Expr*,SrcList*,int); int sqliteAuthCheck(Parse*,int, const char*, const char*, const char*); + void sqliteAuthContextPush(Parse*, AuthContext*, const char*); + void sqliteAuthContextPop(AuthContext*); #else # define sqliteAuthRead(a,b,c,d) # define sqliteAuthCheck(a,b,c,d) SQLITE_OK +# define sqliteAuthContextPush(a,b,c) +# define sqliteAuthContextPop(a) #endif void sqliteAttach(Parse*, Token*, Token*); void sqliteDetach(Parse*, Token*); diff --git a/src/trigger.c b/src/trigger.c index 0abe7ee0d6..b07b8c5a87 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -661,7 +661,7 @@ int sqliteCodeRowTrigger( int endTrigger; SrcList dummyTablist; Expr * whenExpr; - const char *zSavedAuthContext; + AuthContext sContext; dummyTablist.nSrc = 0; @@ -673,8 +673,7 @@ int sqliteCodeRowTrigger( pTriggerStack->pNext = pParse->trigStack; pTriggerStack->ignoreJump = ignoreJump; pParse->trigStack = pTriggerStack; - zSavedAuthContext = pParse->zAuthContext; - pParse->zAuthContext = pTrigger->name; + sqliteAuthContextPush(pParse, &sContext, pTrigger->name); /* code the WHEN clause */ endTrigger = sqliteVdbeMakeLabel(pParse->pVdbe); @@ -692,7 +691,7 @@ int sqliteCodeRowTrigger( /* Pop the entry off the trigger stack */ pParse->trigStack = pParse->trigStack->pNext; - pParse->zAuthContext = zSavedAuthContext; + sqliteAuthContextPop(&sContext); sqliteFree(pTriggerStack); sqliteVdbeResolveLabel(pParse->pVdbe, endTrigger); diff --git a/src/update.c b/src/update.c index c1961426cf..cd98c82c06 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.63 2003/04/24 01:45:05 drh Exp $ +** $Id: update.c,v 1.64 2003/04/25 17:52:11 drh Exp $ */ #include "sqliteInt.h" @@ -49,6 +49,7 @@ void sqliteUpdate( Expr *pRecnoExpr; /* Expression defining the new record number */ int openAll; /* True if all indices need to be opened */ int isView; /* Trying to update a view */ + AuthContext sContext; /* The authorization context */ int before_triggers; /* True if there are any BEFORE triggers */ int after_triggers; /* True if there are any AFTER triggers */ @@ -57,6 +58,7 @@ void sqliteUpdate( int newIdx = -1; /* index of trigger "new" temp table */ int oldIdx = -1; /* index of trigger "old" temp table */ + sContext.pParse = 0; if( pParse->nErr || sqlite_malloc_failed ) goto update_cleanup; db = pParse->db; assert( pTabList->nSrc==1 ); @@ -74,8 +76,10 @@ void sqliteUpdate( if( sqliteIsReadOnly(pParse, pTab, before_triggers) ){ goto update_cleanup; } - if( isView && sqliteViewGetColumnNames(pParse, pTab) ){ - goto update_cleanup; + if( isView ){ + if( sqliteViewGetColumnNames(pParse, pTab) ){ + goto update_cleanup; + } } aXRef = sqliteMalloc( sizeof(int) * pTab->nCol ); if( aXRef==0 ) goto update_cleanup; @@ -99,20 +103,12 @@ void sqliteUpdate( pParse->nTab++; } - /* Resolve the column names in all the expressions in both the - ** WHERE clause and in the new values. Also find the column index + /* Resolve the column names in all the expressions of the + ** of the UPDATE statement. Also find the column index ** for each column to be updated in the pChanges array. For each ** column to be updated, make sure we have authorization to change ** that column. */ - if( pWhere ){ - if( sqliteExprResolveIds(pParse, base, pTabList, 0, pWhere) ){ - goto update_cleanup; - } - if( sqliteExprCheck(pParse, pWhere, 0, 0) ){ - goto update_cleanup; - } - } chngRecno = 0; for(i=0; inExpr; i++){ if( sqliteExprResolveIds(pParse, base, pTabList, 0, pChanges->a[i].pExpr) ){ @@ -185,6 +181,24 @@ void sqliteUpdate( } } + /* Resolve the column names in all the expressions in the + ** WHERE clause. + */ + if( pWhere ){ + if( sqliteExprResolveIds(pParse, base, pTabList, 0, pWhere) ){ + goto update_cleanup; + } + if( sqliteExprCheck(pParse, pWhere, 0, 0) ){ + goto update_cleanup; + } + } + + /* Start the view context + */ + if( isView ){ + sqliteAuthContextPush(pParse, &sContext, pTab->zName); + } + /* Begin generating code. */ v = sqliteGetVdbe(pParse); @@ -195,7 +209,8 @@ void sqliteUpdate( ** a temporary table. */ if( isView ){ - Select *pView = sqliteSelectDup(pTab->pSelect); + Select *pView; + pView = sqliteSelectDup(pTab->pSelect); sqliteSelect(pParse, pView, SRT_TempTable, base, 0, 0, 0); sqliteSelectDelete(pView); } @@ -422,6 +437,7 @@ void sqliteUpdate( } update_cleanup: + sqliteAuthContextPop(&sContext); sqliteFree(apIdx); sqliteFree(aXRef); sqliteSrcListDelete(pTabList); diff --git a/test/auth.test b/test/auth.test index e003c88c09..84b3802e1b 100644 --- a/test/auth.test +++ b/test/auth.test @@ -12,7 +12,7 @@ # focus of this script is testing the ATTACH and DETACH commands # and related functionality. # -# $Id: auth.test,v 1.8 2003/04/22 20:30:40 drh Exp $ +# $Id: auth.test,v 1.9 2003/04/25 17:52:11 drh Exp $ # set testdir [file dirname $argv0] @@ -1714,5 +1714,74 @@ do_test auth-3.2 { } } {12 112 2 2 {} {} 8 108 8 8 {} {}} +# Make sure the names of views and triggers are passed on on arg4. +# +do_test auth-4.1 { + proc auth {code arg1 arg2 arg3 arg4} { + lappend ::authargs $code $arg1 $arg2 $arg3 $arg4 + return SQLITE_OK + } + set authargs {} + execsql { + UPDATE t2 SET a=a+1; + } + set authargs +} [list \ + SQLITE_READ t2 a main {} \ + SQLITE_UPDATE t2 a main {} \ + SQLITE_INSERT tx {} main r1 \ + SQLITE_READ t2 a main r1 \ + SQLITE_READ t2 a main r1 \ + SQLITE_READ t2 b main r1 \ + SQLITE_READ t2 b main r1 \ + SQLITE_READ t2 c main r1 \ + SQLITE_READ t2 c main r1] +do_test auth-4.2 { + execsql { + CREATE VIEW v1 AS SELECT a+b AS x FROM t2; + CREATE TABLE v1chng(x1,x2); + CREATE TRIGGER r2 INSTEAD OF UPDATE ON v1 BEGIN + INSERT INTO v1chng VALUES(OLD.x,NEW.x); + END; + SELECT * FROM v1; + } +} {115 117} +do_test auth-4.3 { + set authargs {} + execsql { + UPDATE v1 SET x=1 WHERE x=117 + } + set authargs +} [list \ + SQLITE_UPDATE v1 x main {} \ + SQLITE_READ v1 x main {} \ + SQLITE_SELECT {} {} {} v1 \ + SQLITE_READ t2 a main v1 \ + SQLITE_READ t2 b main v1 \ + SQLITE_INSERT v1chng {} main r2 \ + SQLITE_READ v1 x main r2 \ + SQLITE_READ v1 x main r2] +do_test auth-4.4 { + execsql { + CREATE TRIGGER r3 INSTEAD OF DELETE ON v1 BEGIN + INSERT INTO v1chng VALUES(OLD.x,NULL); + END; + SELECT * FROM v1; + } +} {115 117} +do_test auth-4.5 { + set authargs {} + execsql { + DELETE FROM v1 WHERE x=117 + } + set authargs +} [list \ + SQLITE_DELETE v1 {} main {} \ + SQLITE_READ v1 x main {} \ + SQLITE_SELECT {} {} {} v1 \ + SQLITE_READ t2 a main v1 \ + SQLITE_READ t2 b main v1 \ + SQLITE_INSERT v1chng {} main r3 \ + SQLITE_READ v1 x main r3] finish_test