From: stephan Date: Sat, 5 Aug 2023 22:41:36 +0000 (+0000) Subject: Bind sqlite3_set_authorizer() to JNI. X-Git-Tag: version-3.43.0~47^2~93 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=153288dc89cf150853061e840f5b34381eec65fb;p=thirdparty%2Fsqlite.git Bind sqlite3_set_authorizer() to JNI. FossilOrigin-Name: e0fa03135942cd2fe732a74510d380ba78ab230c452168e638f32b4aee04b3f7 --- diff --git a/ext/jni/src/c/sqlite3-jni.c b/ext/jni/src/c/sqlite3-jni.c index 56b86c2577..aba4db5a91 100644 --- a/ext/jni/src/c/sqlite3-jni.c +++ b/ext/jni/src/c/sqlite3-jni.c @@ -412,6 +412,7 @@ struct PerDbStateJni { JniHookState rollbackHook; JniHookState trace; JniHookState updateHook; + JniHookState authHook; #ifdef SQLITE_ENABLE_FTS5 jobject jFtsApi /* global ref to s3jni_fts5_api_from_db() */; #endif @@ -610,6 +611,7 @@ static void PerDbStateJni_set_aside(PerDbStateJni * const s){ UNHOOK(commitHook, 0); UNHOOK(rollbackHook, 0); UNHOOK(updateHook, 0); + UNHOOK(authHook, 0); UNHOOK(collation, 1); UNHOOK(collationNeeded, 1); UNHOOK(busyHandler, 1); @@ -2388,6 +2390,71 @@ JDECL(jobject,1rollback_1hook)(JENV_JSELF,jobject jDb, jobject jHook){ return s3jni_commit_rollback_hook(0, env, jDb, jHook); } +/* sqlite3_set_authorizer() callback proxy. */ +static int s3jni_xAuth(void* pState, int op,const char*z0, const char*z1, + const char*z2,const char*z3){ + PerDbStateJni * const ps = pState; + JNIEnv * const env = ps->env; + jstring const s0 = z0 ? (*env)->NewStringUTF(env, z0) : 0; + jstring const s1 = z1 ? (*env)->NewStringUTF(env, z1) : 0; + jstring const s2 = z2 ? (*env)->NewStringUTF(env, z2) : 0; + jstring const s3 = z3 ? (*env)->NewStringUTF(env, z3) : 0; + JniHookState const * const pHook = &ps->authHook; + int rc; + + assert( pHook->jObj ); + rc = (*env)->CallIntMethod(env, pHook->jObj, pHook->midCallback, (jint)op, + s0, s1, s3, s3); + IFTHREW{ + EXCEPTION_WARN_CALLBACK_THREW("sqlite3_set_authorizer() callback"); + EXCEPTION_CLEAR; + } + UNREF_L(s0); + UNREF_L(s1); + UNREF_L(s2); + UNREF_L(s3); + return rc; +} + +JDECL(jint,1set_1authorizer)(JENV_JSELF,jobject jDb, jobject jHook){ + PerDbStateJni * const ps = PerDbStateJni_for_db(env, jDb, 0, 0); + JniHookState * const pHook = ps ? &ps->authHook : 0; + + if( !ps ) return SQLITE_MISUSE; + else if( !jHook ){ + JniHookState_unref(env, pHook, 0); + return (jint)sqlite3_set_authorizer( ps->pDb, 0, 0 ); + }else{ + int rc = 0; + if( pHook->jObj ){ + if( (*env)->IsSameObject(env, pHook->jObj, jHook) ){ + /* Same object - this is a no-op. */ + return 0; + } + JniHookState_unref(env, pHook, 0); + } + pHook->jObj = REF_G(jHook); + pHook->klazz = REF_G((*env)->GetObjectClass(env, jHook)); + pHook->midCallback = (*env)->GetMethodID(env, pHook->klazz, + "xAuth", + "(I" + "Ljava/lang/String;" + "Ljava/lang/String;" + "Ljava/lang/String;" + "Ljava/lang/String;" + ")I"); + IFTHREW { + JniHookState_unref(env, pHook, 0); + return s3jni_db_error(ps->pDb, SQLITE_ERROR, + "Error setting up Java parts of authorizer hook."); + } + rc = sqlite3_set_authorizer(ps->pDb, s3jni_xAuth, ps); + if( rc ) JniHookState_unref(env, pHook, 0); + return rc; + } +} + + JDECL(void,1set_1last_1insert_1rowid)(JENV_JSELF, jobject jpDb, jlong rowId){ sqlite3_set_last_insert_rowid(PtrGet_sqlite3_context(jpDb), (sqlite3_int64)rowId); diff --git a/ext/jni/src/c/sqlite3-jni.h b/ext/jni/src/c/sqlite3-jni.h index d05bf77e45..45a046c99d 100644 --- a/ext/jni/src/c/sqlite3-jni.h +++ b/ext/jni/src/c/sqlite3-jni.h @@ -1371,6 +1371,14 @@ JNIEXPORT void JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1result_1text64 JNIEXPORT jobject JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1rollback_1hook (JNIEnv *, jclass, jobject, jobject); +/* + * Class: org_sqlite_jni_SQLite3Jni + * Method: sqlite3_set_authorizer + * Signature: (Lorg/sqlite/jni/sqlite3;Lorg/sqlite/jni/Authorizer;)I + */ +JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1set_1authorizer + (JNIEnv *, jclass, jobject, jobject); + /* * Class: org_sqlite_jni_SQLite3Jni * Method: sqlite3_set_last_insert_rowid diff --git a/ext/jni/src/org/sqlite/jni/Authorizer.java b/ext/jni/src/org/sqlite/jni/Authorizer.java new file mode 100644 index 0000000000..b10567716c --- /dev/null +++ b/ext/jni/src/org/sqlite/jni/Authorizer.java @@ -0,0 +1,36 @@ +/* +** 2023-08-05 +** +** 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 find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** This file is part of the JNI bindings for the sqlite3 C API. +*/ +package org.sqlite.jni; + +/** + A wrapper for use with sqlite3_set_authorizer(). +*/ +public interface Authorizer { + /** + Must functions as described for the sqlite3_set_authorizer() + callback, with one caveat: the string values passed here were + initially (at the C level) encoded in standard UTF-8. If they + contained any constructs which are not compatible with MUTF-8, + these strings will not have the expected values. The strings + passed through the authorizer would only be adversely affected by + that if the database tables and columns use "highly exotic" + names. Any names which contain no NUL bytes, nor characters + outside of the Basic Multilingual Plane are unaffected by this + discrepancy. + + Must not throw. + */ + int xAuth(int opId, @Nullable String s1, @Nullable String s2, + @Nullable String s3, @Nullable String s4); +} diff --git a/ext/jni/src/org/sqlite/jni/SQLite3Jni.java b/ext/jni/src/org/sqlite/jni/SQLite3Jni.java index 9c8e1321c4..1f7180f14a 100644 --- a/ext/jni/src/org/sqlite/jni/SQLite3Jni.java +++ b/ext/jni/src/org/sqlite/jni/SQLite3Jni.java @@ -103,12 +103,13 @@ public final class SQLite3Jni { primarily for testing of the JNI bindings and is not information which client-level code should use to make any informed decisions. -*/ + */ public static synchronized native boolean uncacheJniEnv(); ////////////////////////////////////////////////////////////////////// - // Maintenance reminder: please keep the functions alphabetized. - // The SQLITE_... values. on the other hand, are grouped by category. + // Maintenance reminder: please keep the sqlite3_.... functions + // alphabetized. The SQLITE_... values. on the other hand, are + // grouped by category. public static int sqlite3_bind_blob(@NotNull sqlite3_stmt stmt, int ndx, @Nullable byte[] data){ @@ -725,6 +726,10 @@ public final class SQLite3Jni { public static native RollbackHook sqlite3_rollback_hook(@NotNull sqlite3 db, @Nullable RollbackHook hook); + //! Sets or unsets (if auth is null) the current authorizer. + public static native int sqlite3_set_authorizer(@NotNull sqlite3 db, + @Nullable Authorizer auth); + public static native void sqlite3_set_last_insert_rowid(@NotNull sqlite3 db, long rowid); public static native int sqlite3_sleep(int ms); diff --git a/ext/jni/src/org/sqlite/jni/Tester1.java b/ext/jni/src/org/sqlite/jni/Tester1.java index df7b0ad82f..a5020663a6 100644 --- a/ext/jni/src/org/sqlite/jni/Tester1.java +++ b/ext/jni/src/org/sqlite/jni/Tester1.java @@ -82,7 +82,8 @@ public class Tester1 { } if( 0==sqlChunk.length ) break; rc = sqlite3_prepare_v2(db, sqlChunk, stmt, oTail); - affirm(0 == rc); + if(throwOnError) affirm(0 == rc); + else if( 0!=rc ) break; pos = oTail.getValue(); affirm(0 != stmt.getNativePointer()); while( SQLITE_ROW == (rc = sqlite3_step(stmt)) ){ @@ -97,6 +98,7 @@ public class Tester1 { } } } + sqlite3_finalize(stmt); if(SQLITE_ROW==rc || SQLITE_DONE==rc) rc = 0; return rc; } @@ -949,6 +951,28 @@ public class Tester1 { } } + private static void testAuthorizer(){ + final sqlite3 db = createNewDb(); + final ValueHolder counter = new ValueHolder<>(0); + final ValueHolder authRc = new ValueHolder<>(0); + final Authorizer auth = new Authorizer(){ + public int xAuth(int op, String s0, String s1, String s2, String s3){ + ++counter.value; + //outln("xAuth(): "+s0+" "+s1+" "+s2+" "+s3); + return authRc.value; + } + }; + execSql(db, "CREATE TABLE t(a); INSERT INTO t(a) VALUES('a'),('b'),('c')"); + sqlite3_set_authorizer(db, auth); + execSql(db, "UPDATE t SET a=1"); + affirm( 1 == counter.value ); + authRc.value = SQLITE_DENY; + int rc = execSql(db, false, "UPDATE t SET a=2"); + affirm( SQLITE_AUTH==rc ); + // TODO: expand these tests considerably + sqlite3_close(db); + } + private static void testSleep(){ out("Sleeping briefly... "); sqlite3_sleep(600); @@ -981,6 +1005,7 @@ public class Tester1 { testCommitHook(); testRollbackHook(); testUpdateHook(); + testAuthorizer(); testFts5(); //testSleep(); if(liArgs.indexOf("-v")>0){ diff --git a/manifest b/manifest index 9898624e78..84a488eff3 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Refactor\sthe\sper-JNIEnv\scache\sfrom\sa\sfixed-size\sstatic\sarray\sto\sa\slinked\slist\sof\sdynamically-allocated\sentries.\sUncache\sall\sper-db\sstate\s(which\sis\snecessarily\sJNIEnv-specific)\swhen\sthe\scorresponding\sJNIEnv\sis\suncached. -D 2023-08-05T21:35:58.833 +C Bind\ssqlite3_set_authorizer()\sto\sJNI. +D 2023-08-05T22:41:36.472 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -232,8 +232,9 @@ F ext/icu/icu.c c074519b46baa484bb5396c7e01e051034da8884bad1a1cb7f09bbe6be3f0282 F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a32075a8 F ext/jni/GNUmakefile bb4cd99bd8da534215cb6d278f05a626283eb5d2e8aebdb4d35e548637d35a9a F ext/jni/README.md 6ff7e1f4100dee980434a6ee37a199b653bceec62e233a6e2ccde6e7ae0c58bf -F ext/jni/src/c/sqlite3-jni.c a894cb1b6a7479d376d98f7df0e29a713d2b6b6cbc0d4543505b90eb38593592 -F ext/jni/src/c/sqlite3-jni.h cd9b6367a260f55a14833861ceb1d87cb729c5414ba5d26fbb8854b0f22c7249 +F ext/jni/src/c/sqlite3-jni.c b81dcf92a1fbd7ada98dbc0f526b02e9e97e2be84cb331092e933c7d8feeafe2 +F ext/jni/src/c/sqlite3-jni.h 1db6075134d7efc71f634e4a212e41d0178346e68c7c615f220d753e4bd23382 +F ext/jni/src/org/sqlite/jni/Authorizer.java 189e7fa2155466ded5a52eed1ccb46581b5b45d70fcef49f538c0b93ea88e337 F ext/jni/src/org/sqlite/jni/BusyHandler.java 1b1d3e5c86cd796a0580c81b6af6550ad943baa25e47ada0dcca3aff3ebe978c F ext/jni/src/org/sqlite/jni/Collation.java 8dffbb00938007ad0967b2ab424d3c908413af1bbd3d212b9c9899910f1218d1 F ext/jni/src/org/sqlite/jni/CollationNeeded.java ebc7cd96d46a70daa76016a308e80f70a3f21d3282787c8d139aa840fdcb1bd7 @@ -249,8 +250,8 @@ F ext/jni/src/org/sqlite/jni/OutputPointer.java 013f2b5fe569d0585a695f5cfa605a3b F ext/jni/src/org/sqlite/jni/ProgressHandler.java 5979450e996416d28543f1d42634d308439565a99332a8bd84e424af667116cc F ext/jni/src/org/sqlite/jni/RollbackHook.java b04c8abcc6ade44a8a57129e33765793f69df0ba909e49ba18d73f4268d92564 F ext/jni/src/org/sqlite/jni/SQLFunction.java 09ce81c1c637e31c3a830d4c859cce95d65f5e02ff45f8bd1985b3479381bc46 -F ext/jni/src/org/sqlite/jni/SQLite3Jni.java f8fec24eea4ff9a62467648f377391506883eff4bedfc50d69d8cb3dc78d1ab9 -F ext/jni/src/org/sqlite/jni/Tester1.java 868b5ea60b788a43f8b15c1b642015341fed8856abb1bb74e2eb4845ade50a4e +F ext/jni/src/org/sqlite/jni/SQLite3Jni.java 850012ad011d5d60a8aaaf9b8db562c60277988982793135814892e82ac77b97 +F ext/jni/src/org/sqlite/jni/Tester1.java 214985f8a700ac56a174809c04196215fef5d7bb8b86e095d9d0abf436349ffb F ext/jni/src/org/sqlite/jni/TesterFts5.java cf2d687baafffdeba219b77cf611fd47a0556248820ea794ae3e8259bfbdc5ee F ext/jni/src/org/sqlite/jni/Tracer.java a5cece9f947b0af27669b8baec300b6dd7ff859c3e6a6e4a1bd8b50f9714775d F ext/jni/src/org/sqlite/jni/UpdateHook.java e58645a1727f8a9bbe72dc072ec5b40d9f9362cb0aa24acfe93f49ff56a9016d @@ -2081,8 +2082,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 7468f8761bece58f7ced3d112bbe2fb454432d9c54c9b96cedb5a15bc2926d0f -R c28f39c95821b6209d9e0ded55b1b7ca +P 9dd8b78419e19e88bc3fbff9bf200390b146b2461af2bb6b93d8467036619e33 +R bf3d1c30171f035a2002cb68468caf2a U stephan -Z 6d5410b49d781e986fb3ebb97da80215 +Z a910bd2897a92249409319f7eba80e4a # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 27cf161b3c..1516c35375 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -9dd8b78419e19e88bc3fbff9bf200390b146b2461af2bb6b93d8467036619e33 \ No newline at end of file +e0fa03135942cd2fe732a74510d380ba78ab230c452168e638f32b4aee04b3f7 \ No newline at end of file