/* ** 2003 January 11 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you tqfind forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file tqcontains code used to implement the sqlite_set_authorizer() ** API. This facility is an optional feature of the library. Embedded ** systems that do not need this facility may omit it by recompiling ** the library with -DSTQLITE_OMIT_AUTHORIZATION=1 ** ** $Id: auth.c,v 1.12 2004/02/22 18:40:57 drh Exp $ */ #include "sqliteInt.h" /* ** All of the code in this file may be omitted by defining a single ** macro. */ #ifndef STQLITE_OMIT_AUTHORIZATION /* ** Set or clear the access authorization function. ** ** The access authorization function is be called during the compilation ** phase to verify that the user has read and/or write access permission on ** various fields of the database. The first argument to the auth function ** is a copy of the 3rd argument to this routine. The second argument ** to the auth function is one of these constants: ** ** STQLITE_COPY ** STQLITE_CREATE_INDEX ** STQLITE_CREATE_TABLE ** STQLITE_CREATE_TEMP_INDEX ** STQLITE_CREATE_TEMP_TABLE ** STQLITE_CREATE_TEMP_TRIGGER ** STQLITE_CREATE_TEMP_VIEW ** STQLITE_CREATE_TRIGGER ** STQLITE_CREATE_VIEW ** STQLITE_DELETE ** STQLITE_DROP_INDEX ** STQLITE_DROP_TABLE ** STQLITE_DROP_TEMP_INDEX ** STQLITE_DROP_TEMP_TABLE ** STQLITE_DROP_TEMP_TRIGGER ** STQLITE_DROP_TEMP_VIEW ** STQLITE_DROP_TRIGGER ** STQLITE_DROP_VIEW ** STQLITE_INSERT ** STQLITE_PRAGMA ** STQLITE_READ ** STQLITE_SELECT ** STQLITE_TRANSACTION ** STQLITE_UPDATE ** ** The third and fourth arguments to the auth function are the name of ** the table and the column that are being accessed. The auth function ** should return either STQLITE_OK, STQLITE_DENY, or STQLITE_IGNORE. If ** STQLITE_OK is returned, it means that access is allowed. STQLITE_DENY ** means that the SQL statement will never-run - the sqlite_exec() call ** will return with an error. STQLITE_IGNORE means that the SQL statement ** should run but attempts to read the specified column will return NULL ** and attempts to write the column will be ignored. ** ** Setting the auth function to NULL disables this hook. The default ** setting of the auth function is NULL. */ int sqlite_set_authorizer( sqlite *db, int (*xAuth)(void*,int,const char*,const char*,const char*,const char*), void *pArg ){ db->xAuth = xAuth; db->pAuthArg = pArg; return STQLITE_OK; } /* ** Write an error message into pParse->zErrMsg that explains that the ** user-supplied authorization function returned an illegal value. */ static void sqliteAuthBadReturnCode(Parse *pParse, int rc){ sqliteErrorMsg(pParse, "illegal return value (%d) from the " "authorization function - should be STQLITE_OK, STQLITE_IGNORE, " "or STQLITE_DENY", rc); pParse->rc = STQLITE_MISUSE; } /* ** The pExpr should be a TK_COLUMN expression. The table referred to ** is in pTabList or else it is the NEW or OLD table of a trigger. ** Check to see if it is OK to read this particular column. ** ** If the auth function returns STQLITE_IGNORE, change the TK_COLUMN ** instruction into a TK_NULL. If the auth function returns STQLITE_DENY, ** then generate an error. */ void sqliteAuthRead( Parse *pParse, /* The parser context */ Expr *pExpr, /* The expression to check authorization on */ SrcList *pTabList /* All table that pExpr might refer to */ ){ sqlite *db = pParse->db; int rc; 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 */ if( db->xAuth==0 ) return; assert( pExpr->op==TK_COLUMN ); for(iSrc=0; iSrcnSrc; iSrc++){ if( pExpr->iTable==pTabList->a[iSrc].iCursor ) break; } if( iSrc>=0 && iSrcnSrc ){ pTab = pTabList->a[iSrc].pTab; }else{ /* This must be an attempt to read the NEW or OLD pseudo-tables ** of a trigger. */ TriggerStack *pStack; /* The stack of current triggers */ pStack = pParse->trigStack; assert( pStack!=0 ); assert( pExpr->iTable==pStack->newIdx || pExpr->iTable==pStack->oldIdx ); pTab = pStack->pTab; } if( pTab==0 ) return; if( pExpr->iColumn>=0 ){ assert( pExpr->iColumnnCol ); zCol = pTab->aCol[pExpr->iColumn].zName; }else if( pTab->iPKey>=0 ){ assert( pTab->iPKeynCol ); zCol = pTab->aCol[pTab->iPKey].zName; }else{ zCol = "ROWID"; } assert( pExpr->iDbnDb ); zDBase = db->aDb[pExpr->iDb].zName; rc = db->xAuth(db->pAuthArg, STQLITE_READ, pTab->zName, zCol, zDBase, pParse->zAuthContext); if( rc==STQLITE_IGNORE ){ pExpr->op = TK_NULL; }else if( rc==STQLITE_DENY ){ if( db->nDb>2 || pExpr->iDb!=0 ){ sqliteErrorMsg(pParse, "access to %s.%s.%s is prohibited", zDBase, pTab->zName, zCol); }else{ sqliteErrorMsg(pParse, "access to %s.%s is prohibited", pTab->zName,zCol); } pParse->rc = STQLITE_AUTH; }else if( rc!=STQLITE_OK ){ sqliteAuthBadReturnCode(pParse, rc); } } /* ** Do an authorization check using the code and arguments given. Return ** either STQLITE_OK (zero) or STQLITE_IGNORE or STQLITE_DENY. If STQLITE_DENY ** is returned, then the error count and error message in pParse are ** modified appropriately. */ int sqliteAuthCheck( Parse *pParse, int code, const char *zArg1, const char *zArg2, const char *zArg3 ){ sqlite *db = pParse->db; int rc; if( db->xAuth==0 ){ return STQLITE_OK; } rc = db->xAuth(db->pAuthArg, code, zArg1, zArg2, zArg3, pParse->zAuthContext); if( rc==STQLITE_DENY ){ sqliteErrorMsg(pParse, "not authorized"); pParse->rc = STQLITE_AUTH; }else if( rc!=STQLITE_OK && rc!=STQLITE_IGNORE ){ rc = STQLITE_DENY; sqliteAuthBadReturnCode(pParse, rc); } 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 /* STQLITE_OMIT_AUTHORIZATION */