@Wez: Whoop, just found you as maintainer in Pecl and send the same request direct to you, sorry!
2006/11/16, Wez Furlong <[EMAIL PROTECTED]>:
Two comments about the patch: - could you create a unified diff and post that instead?
Here it is!
- static local variable usage is not thread safe; state should be stored in the pdo_dbh_t structure.
Makes sense, even for cleanup. pdo_sqlite_request_shutdown cant free the callback-zval right now.
And one concern: I deliberately left this feature unimplemented so far because the authorization callback will happen "a lot", and frequent callbacks into PHP script will make things slower.
It is only called at compiletime of a query! I think thats not as hard! Maybe it could be an optional feature?
I suggest that you adjust your patch to cache the function callback information in the pdo_dbh_t to reduce some of that overhead, and run some benchmarks for a simple authorizer function in PHP that always returns true vs the same script with no authorizer, so that we get a feel for what kind of impact that has for various common queries.
The Sqlite-Api keeps the user-authorizer in the userdata-void-pointer. The static definition is only ment for clean up!
One other thing that is important is to ensure that the PHP safe_mode/open_basedir checks have higher priority than the PHP script callback. If safe_mode/open_basedir decide that the path is not accessible, then the PHP script must not be able to override that. However, if safe_mode/open_basedir say that access is ok, the PHP script can optionally override that decision.
Have a look on my authorizer, the user-authorizer is only called if your rules gives SQLITE_OK. The user-authorizer is called from a default authorizer, not from the sqlite-api!
--Wez.
Regards, Mario
On 11/16/06, Mario Wolff <[EMAIL PROTECTED]> wrote: > Hello list, > i've extended sqlite_driver to get access to the authorizer-feature of > sqlite. This is my first contact with the Zend-API and my last c skill > is more than a bit outdated. > Could someone review/cleanup my code to get it merged to the > distribution? Hint and comment welcome! > Thanks, > Mario Wolff > > PS: Patch applys against 5.2.0! > > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: http://www.php.net/unsub.php > > >
--- php-5.2.0/ext/pdo_sqlite/sqlite_driver.c 2006-09-16 20:30:03.000000000 +0200 +++ php-5.2.0-new/ext/pdo_sqlite/sqlite_driver.c 2006-11-16 13:38:33.985989144 +0100 @@ -31,6 +31,8 @@ #include "php_pdo_sqlite_int.h" #include "zend_exceptions.h" +static int authorizer(void *autharg, int access_type, const char *arg3, const char *arg4, + const char *arg5, const char *arg6); int _pdo_sqlite_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, const char *file, int line TSRMLS_DC) /* {{{ */ { pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *)dbh->driver_data; @@ -593,9 +595,59 @@ RETURN_FALSE; } /* }}} */ + +/* {{{ bool SQLite::sqliteSetAuthorizer(string name, mixed callback [, int argcount]) + Registers a UDF with the sqlite db handle */ +static PHP_METHOD(SQLite, sqliteSetAuthorizer) +{ + static zval*user_authorizer=NULL; + struct pdo_sqlite_func *func; + zval *callback=NULL; + char *cbname = NULL; + pdo_dbh_t *dbh; + pdo_sqlite_db_handle *H; + int ret; + + if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z", + &callback)) { + RETURN_FALSE; + } + + dbh = zend_object_store_get_object(getThis() TSRMLS_CC); + PDO_CONSTRUCT_CHECK; + H = (pdo_sqlite_db_handle *)dbh->driver_data; + + if( callback==NULL || callback->type == IS_STRING && ! strcmp(callback->value.str.val,"") ){ + if (user_authorizer!=NULL){ + FREE_ZVAL(user_authorizer); + sqlite3_set_authorizer(H->db, authorizer,NULL); + } + RETURN_TRUE; + } + + if (!zend_is_callable(callback, 0, &cbname)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "function '%s' is not callable", cbname); + efree(cbname); + RETURN_FALSE; + } + efree(cbname); + + + if (user_authorizer!=NULL){ + FREE_ZVAL(user_authorizer); + } + + MAKE_STD_ZVAL(user_authorizer); + ZVAL_STRING(user_authorizer, callback->value.str.val, 1); + sqlite3_set_authorizer(H->db, authorizer, user_authorizer); + RETURN_TRUE; +} +/* }}} */ + static zend_function_entry dbh_methods[] = { PHP_ME(SQLite, sqliteCreateFunction, NULL, ZEND_ACC_PUBLIC) PHP_ME(SQLite, sqliteCreateAggregate, NULL, ZEND_ACC_PUBLIC) + PHP_ME(SQLite, sqliteSetAuthorizer, NULL, ZEND_ACC_PUBLIC) {NULL, NULL, NULL} }; @@ -663,32 +715,147 @@ static int authorizer(void *autharg, int access_type, const char *arg3, const char *arg4, const char *arg5, const char *arg6) { + zval *callback=NULL,*zaccess_type,*zarg3,*zarg4,*zarg5,*zarg6; + int retval=SQLITE_OK; char *filename; - switch (access_type) { - case SQLITE_COPY: { - TSRMLS_FETCH(); - filename = make_filename_safe(arg4 TSRMLS_CC); - if (!filename) { - return SQLITE_DENY; + if (PG(safe_mode) || (PG(open_basedir) && *PG(open_basedir))) { + switch (access_type) { + case SQLITE_COPY: { + TSRMLS_FETCH(); + filename = make_filename_safe(arg4 TSRMLS_CC); + if (!filename) { + retval=SQLITE_DENY; + }else{ + efree(filename); + retval=SQLITE_OK; + } } - efree(filename); - return SQLITE_OK; - } - case SQLITE_ATTACH: { - TSRMLS_FETCH(); - filename = make_filename_safe(arg3 TSRMLS_CC); - if (!filename) { - return SQLITE_DENY; + case SQLITE_ATTACH: { + TSRMLS_FETCH(); + filename = make_filename_safe(arg3 TSRMLS_CC); + if (!filename) { + retval=SQLITE_DENY; + }else{ + efree(filename); + retval=SQLITE_OK; + } } - efree(filename); - return SQLITE_OK; - } - default: - /* access allowed */ - return SQLITE_OK; + default: + /* access allowed */ + retval=SQLITE_OK; + } + } + if( retval==SQLITE_OK && autharg!=NULL ){ + callback=(zval*)autharg; + zval **args[5]; + zend_fcall_info_cache fci_cache = empty_fcall_info_cache; + zval *result = NULL; + zend_fcall_info fci; + char* zCode; + switch( access_type ){ + 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; + case SQLITE_ATTACH : zCode="SQLITE_ATTACH"; break; + case SQLITE_DETACH : zCode="SQLITE_DETACH"; break; + case SQLITE_ALTER_TABLE : zCode="SQLITE_ALTER_TABLE"; break; + case SQLITE_REINDEX : zCode="SQLITE_REINDEX"; break; + case SQLITE_ANALYZE : zCode="SQLITE_ANALYZE"; break; + case SQLITE_CREATE_VTABLE : zCode="SQLITE_CREATE_VTABLE"; break; + case SQLITE_DROP_VTABLE : zCode="SQLITE_DROP_VTABLE"; break; + default : zCode="????"; break; + } + MAKE_STD_ZVAL(zaccess_type); + ZVAL_STRING(zaccess_type,zCode, 1); + args[0]=&zaccess_type; + + MAKE_STD_ZVAL(zarg3); + if( arg3!=NULL ){ + ZVAL_STRING(zarg3,(char*)arg3, 1); + }else{ + ZVAL_STRING(zarg3,"", 1); + } + args[1]=&zarg3; + + MAKE_STD_ZVAL(zarg4); + if( arg4!=NULL ){ + ZVAL_STRING(zarg4,(char*)arg4, 1); + }else{ + ZVAL_STRING(zarg4,"", 1); + } + args[2]=&zarg4; + + MAKE_STD_ZVAL(zarg5); + if( arg5!=NULL ){ + ZVAL_STRING(zarg5,(char*)arg5, 1); + }else{ + ZVAL_STRING(zarg5,"", 1); + } + args[3]=&zarg5; + + MAKE_STD_ZVAL(zarg6); + if( arg6!=NULL ){ + ZVAL_STRING(zarg6,(char*)arg6, 1); + }else{ + ZVAL_STRING(zarg6,"", 1); + } + args[4]=&zarg6; + + fci.size = sizeof(fci); + fci.function_table = EG(function_table); + fci.function_name = callback; + fci.symbol_table = NULL; + fci.object_pp = NULL; + fci.retval_ptr_ptr = &result; + fci.param_count = 5; + fci.params = args; + fci.no_separation = 0; + + if (zend_call_function(&fci, &fci_cache TSRMLS_CC) == SUCCESS && result) { + if( result->type==IS_BOOL ){ + retval=(result->value.lval==0); + }else if( result->type==IS_LONG ){ + retval=result->value.lval; + }else{ + php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid return from authorizer, need bool or int"); + retval=SQLITE_DENY; + } + } else { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "An error occurred while invoking the reduction callback"); + retval=SQLITE_DENY; + } + + FREE_ZVAL(zaccess_type); + FREE_ZVAL(zarg3); + FREE_ZVAL(zarg4); + FREE_ZVAL(zarg5); + FREE_ZVAL(zarg6); + } + return retval; } static int pdo_sqlite_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_DC) /* {{{ */ @@ -721,9 +888,7 @@ goto cleanup; } - if (PG(safe_mode) || (PG(open_basedir) && *PG(open_basedir))) { - sqlite3_set_authorizer(H->db, authorizer, NULL); - } + sqlite3_set_authorizer(H->db, authorizer, NULL); if (driver_options) { timeout = pdo_attr_lval(driver_options, PDO_ATTR_TIMEOUT, timeout TSRMLS_CC);
-- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php