]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Bind sqlite3_set_authorizer() to JNI.
authorstephan <stephan@noemail.net>
Sat, 5 Aug 2023 22:41:36 +0000 (22:41 +0000)
committerstephan <stephan@noemail.net>
Sat, 5 Aug 2023 22:41:36 +0000 (22:41 +0000)
FossilOrigin-Name: e0fa03135942cd2fe732a74510d380ba78ab230c452168e638f32b4aee04b3f7

ext/jni/src/c/sqlite3-jni.c
ext/jni/src/c/sqlite3-jni.h
ext/jni/src/org/sqlite/jni/Authorizer.java [new file with mode: 0644]
ext/jni/src/org/sqlite/jni/SQLite3Jni.java
ext/jni/src/org/sqlite/jni/Tester1.java
manifest
manifest.uuid

index 56b86c2577a79f2cf9e7dec7ff24cf07ec890dc5..aba4db5a917b2ccf86c0f1a7e51a9ac7c8886808 100644 (file)
@@ -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);
index d05bf77e4562898e98e2590220d580088e5cec7b..45a046c99d5fe06866c4218ce97ef4abfa64ef3e 100644 (file)
@@ -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 (file)
index 0000000..b105677
--- /dev/null
@@ -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);
+}
index 9c8e1321c4639487de29f42e17498dfd4e638af3..1f7180f14a56c9210496beb0a51904b143609b9d 100644 (file)
@@ -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);
index df7b0ad82f47ca3352044656756f247c8ba229fe..a5020663a6115ff1527764f245e6b3312dda08a5 100644 (file)
@@ -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<Integer> counter = new ValueHolder<>(0);
+    final ValueHolder<Integer> 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){
index 9898624e78b906eb804e600abe8dc664d10cee6f..84a488eff35928908dd33a86c16681f48bb706fc 100644 (file)
--- 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.
index 27cf161b3c277134180caed2c1f1410357ca50a6..1516c3537530b978b962ea543afe0f0587ddac1f 100644 (file)
@@ -1 +1 @@
-9dd8b78419e19e88bc3fbff9bf200390b146b2461af2bb6b93d8467036619e33
\ No newline at end of file
+e0fa03135942cd2fe732a74510d380ba78ab230c452168e638f32b4aee04b3f7
\ No newline at end of file