For one of my projects, I want to implement a complete PAM implementation for Java (application side and module side as well).
Right now, I’m on the application side. I took jpam as a base but I stumble upon a problem, and after some hours of searching around I still cannot find the solution to my problem :/
This is the current code:
JNIEXPORT jint JNICALL Java_org_eel_kitchen_pam_PamHandle_authenticate(
JNIEnv *pEnv, jobject pObj, jstring pServiceName, jstring pUsername,
jstring pPassword, jboolean debug)
{
pam_handle_t *pamh = NULL;
int retval;
/*
* TODO: unclear, see what's what
*
* With my first tests, it appears that GetStringUTFChars() makes the JVM
* crash if memory cannot be allocated... But an array copy was made. See
* what happens if the JVM decides NOT to make a copy. Right now it is
* assumed that allocations succeed. And the JNI spec says
* GetStringUTFChars() does NOT throw an OOM on failure.
*/
service_name = (*pEnv)->GetStringUTFChars(pEnv, pServiceName, NULL);
username = (*pEnv)->GetStringUTFChars(pEnv, pUsername, NULL);
password = (*pEnv)->GetStringUTFChars(pEnv, pPassword, NULL);
/* Get a handle to a PAM instance */
retval = pam_start(service_name, username, &PAM_converse, &pamh);
if (retval != PAM_SUCCESS) {
pr_debug("pam_start failed for service %s: %s\n", service_name,
pam_strerror(NULL, retval));
goto out_nohandle;
}
pam_set_item(pamh, PAM_AUTHTOK, password);
retval = pam_authenticate(pamh, 0);
/* Is user permitted access? */
if (retval != PAM_SUCCESS) {
pr_debug("failed to authenticate user %s: %s\n", username,
pam_strerror(NULL, retval));
goto out_free;
}
retval = pam_acct_mgmt(pamh, 0);
if (retval != PAM_SUCCESS)
pr_debug("failed to setup account for user %s: %s\n", username,
pam_strerror(NULL, retval));
out_free:
/* Clean up our handles and variables */
if (pam_end(pamh, retval) != PAM_SUCCESS) {
pamh = NULL;
pr_debug("Fuchs! Failed to release PAM handle\n");
}
out_nohandle:
(*pEnv)->ReleaseStringUTFChars(pEnv, pServiceName, service_name);
(*pEnv)->ReleaseStringUTFChars(pEnv, pUsername, username);
(*pEnv)->ReleaseStringUTFChars(pEnv, pPassword, password);
return retval;
}
What I want here is keep a reference to pamh for all instances of PamHandle. How is this done?
edit: OK, I have the answer to this, and now there’s the cleanup part: do I use finalize() to call a native cleanup method then super.finalize();, or is there a JNI function which is triggered by the GC which I can/must implement?
Use a long to store a pointer to pam_handle_t.
Java-side it would look like
Of course you could encapsulate this inside a class, so you could have the interface.
C side it would look like this:
This would allow you to have one pam_handle_t per instance.
It is also alot more performant to manually pass the integer each time, rather than passing an object, and then having to access the object’s field.
EDIT
Also, if you are worried about the jlong not being able to hold a pointer correctly, a jlong is guaranteed to be 64-bit. So, a jlong will work for this case all the way until we start getting 128-bit integers( a long long way away).