A Java binding for libpam.
kohsuke / libpam4j Goto Github PK
View Code? Open in Web Editor NEWlibpam4j
Home Page: http://libpam4j.kohsuke.org/
License: MIT License
libpam4j
Home Page: http://libpam4j.kohsuke.org/
License: MIT License
We are using Jenkins docker image in our CI.
On 23/08/2023 ( LTS 2.414.1 ), the image is updated from Debian 11 to Debian 12.
In this update, libpam-runtime move from 1.4.0 to 1.5.0
Since this date, LDAP Authentication Failed.
We suspect an incompatibility with the new libpam-runtime.
On some CentOS systems (not all, but seen in 6.2 and 6.5) I'm seeing a crash when there are many (eg, 50) threads calling PAM.pam_authenticate(). Each thread creates and uses its own PAM object (I know they are not thread-safe).
Any idea what the problem might be or where to look for system differences triggering this crash?
The /etc/pam.d/login (the PAM service I'm using) is identical on a working vs failing system. No difference java 1.6 vs 1.7.
I only found one other occurrence of this crash in a google search, mentioned here:
Here's the stack from hs_error.log:
Stack: [0x00007fe234f5b000,0x00007fe23505c000], sp=0x00007fe2350588a8, free
space=1014k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
C [libc.so.6+0x7b6ec] cfree+0x1c
Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
j com.sun.jna.Native.invokeInt(JI[Ljava/lang/Object;)I+0
j com.sun.jna.Function.invoke([Ljava/lang/Object;Ljava/lang/Class;Z)Ljava/lang/Object;+333
j com.sun.jna.Function.invoke(Ljava/lang/Class;[Ljava/lang/Object;Ljava/util/Map;)Ljava/lang/Object;+214
j com.sun.jna.Library$Handler.invoke(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;+341
j com.sun.proxy.$Proxy7.pam_authenticate(Lorg/jvnet/libpam/impl/PAMLibrary$pam_handle_t;I)I+23
j org.jvnet.libpam.PAM.authenticate(Ljava/lang/String;Ljava/lang/String;)Lorg/jvnet/libpam/UnixUser;+34
Hi @kohsuke,
Glassfish is using libpam4j and some of the tests are failing in windows 10. I believe libpam4j does not support windows. Is there a workaround ?
2019-10-30 15:51:03.239 ERROR 20613 --- [nio-8443-exec-4] o.o.a.s.CustomAuthenticationProvider : PAM authentication failed: pam_authenticate failed : Authentication failure -- org.jvnet.libpam.PAMException: pam_authenticate failed : Authentication failure
at org.jvnet.libpam.PAM.check(PAM.java:106)
at org.jvnet.libpam.PAM.authenticate(PAM.java:124)
Getting this in my program. Tryied on three different linux OS same result. Can't seem to figure out what this message is telling me. Did I miss a step somewhere?
pamtester -v login **** authenticate
This works... but fails via the java program running as the same user.
Tried on Fedora 27, Fedora 29, even a Oracle Linux 7 I had kicking around.
I use libpam4j in my project. You can provide an example implementation of the "password()" method to change the password?
I attempted to updated to JNA 4.2.2, but libpam4j authentication (simple unix passwd file) fails on Linux (Centos 6.5 and 6.7). OSX seems to still work fine so the issue isn't consistent. JNA 4.1.0 works consistently across OS types
When the PAM module pam_tally2 is in use, it tallies the login attempts, in order to lock out accounts after a sequence of consecutive failed attempts. It is supposed to reset the count after a successful login, but it uses calls to pam_setcred
to know that the full PAM stack succeeded in pam_authenticate
, and libpam4j does not call this.
We recently noticed that the UnixUser getGroups method was occasionally returning garbage; other user names, incorrect groups and even strings containing non-alphanumeric characters. It turns out that the getgrgid function used in the constructor of UnixUser is not thread safe so when authenticating users in multiple threads concurrently you can get these unexpected results. The getgrgid function needs to be swapped out for getgrgid_r. Unfortunately I'm not a JNA expert so as a quick fix I just put a synchronize block around the for loop that gets the group names. I will post a proper fix when I get some time to learn JNA.
Hi,
My application is running under non-root privileges and when we are trying to authenticate the root user we are getting this exception.
org.jvnet.libpam.PAMException: pam_authenticate failed : Authentication failure
at org.jvnet.libpam.PAM.check(PAM.java:110) ~[libpam4j-1.11.jar:?]
at org.jvnet.libpam.PAM.authenticate(PAM.java:128) ~[libpam4j-1.11.jar:?]
Thank you in advance.
I recently catched up on the CVE regarding proper account validation. I guess this is why pam_acct_mgmnt was added and even backported to 1.4.x. However, here's the problem: somehow pam_setcred() also got in.
According to the Linux man pages the user, aka the "pam service" needs proper permissions in order to actually apply credential changes -- if applicable. Thus, if the user who owns the jenkins process has no permission to actually execute pam_setcred() the login fails.
Please refer to:
and
Usually, people then then to run jenkins as root which, IMHO, is not an option at all. Thus, I was wondering if the pam_setcred() method is a) really required or b) can be marked as optional in Jenkin's pam auth settings?
Last, people seem to have forked this lib already just to comment this one line :(
Best,
Florian
Right now users authenticated via PAM are conflated with users local to the box.
Steps to reproduce:
set up a PAM service that authenticates external to the system, ie pam_ldap (but do not make this login)
do not set up a local user with the same name
use libpam4j to authenticate
Ideally, the libc based information should be optional additional info.
Is it compatible java8? how to use it? Is there jar file?
Please remove the use of _
as an identifier in the codebase, as this breaks building with Java 9.
Alternatively, change the -source
to 1.8
, which allows this deprecated feature.
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-javadoc-plugin:2.10.4:jar (default-cli) on project libpam4j: MavenReportException: Error while generating Javadoc:
[ERROR] Exit code: 1 - /build/libpam4j-1.4/src/main/java/org/jvnet/libpam/PAM.java:74: error: as of release 9, '_' is a keyword, and may not be used as an identifier
[ERROR] public int callback(int num_msg, Pointer msg, Pointer resp, Pointer _) {
[ERROR] ^
[ERROR] /build/libpam4j-1.4/src/main/java/org/jvnet/libpam/impl/PAMLibrary.java:102: error: as of release 9, '_' is a keyword, and may not be used as an identifier
[ERROR] int callback(int num_msg, Pointer msg, Pointer resp, Pointer _);
[ERROR] ^
[ERROR] /build/libpam4j-1.4/src/main/java/org/jvnet/libpam/impl/PAMLibrary.java:105: error: as of release 9, '_' is a keyword, and may not be used as an identifier
[ERROR] public Pointer _;
[ERROR] ^
[ERROR]
[ERROR] Command line was: /usr/lib/jvm/java-9-openjdk-amd64/bin/javadoc @options @packages
[ERROR]
[ERROR] Refer to the generated Javadoc files in '/build/libpam4j-1.4/target/apidocs' dir.
[ERROR]
[ERROR] -> [Help 1]
I wan to use libpam4j in a production system therefore I started to play with it. I created my first program to test basic funcionality of libpam4j:
public class App
{
public static void main( String[] args) throws Exception
{
UnixUser u = new PAM("login").authenticate(args[0], args[1]);
System.out.println("Groups : " + u.getGroups());
}
}
After ~10 execution the program surprisingly terminated with segfault. The segfault occured in the finalizer thread of JVM after the list of groups was printed to standard output.
The error file can be found here.
Relevant section:
Stack: [0x6bfaf000,0x6c000000], sp=0x6bffe0d0, free space=316k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
C [ld-linux.so.2+0x8ecf] _dl_rtld_di_serinfo+0x3ff
Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
j java.lang.ClassLoader$NativeLibrary.find(Ljava/lang/String;)J+0
j java.lang.ClassLoader.findNative(Ljava/lang/ClassLoader;Ljava/lang/String;)J+49
v ~StubRoutines::call_stub
j com.sun.jna.Native.free(J)V+0
j com.sun.jna.Memory.free(J)V+1
j com.sun.jna.Memory.dispose()V+4
j com.sun.jna.Memory.finalize()V+1
v ~StubRoutines::call_stub
j java.lang.ref.Finalizer.invokeFinalizeMethod(Ljava/lang/Object;)V+0
j java.lang.ref.Finalizer.runFinalizer()V+45
j java.lang.ref.Finalizer.access$100(Ljava/lang/ref/Finalizer;)V+1
j java.lang.ref.Finalizer$FinalizerThread.run()V+24
v ~StubRoutines::call_stub
So it seems the problem occured during Memory object dispose, used in the UnixUser class.
The program was executed with maven and:
Let me know if I have bad version issue.
Unfortunately after 50 execution the program crashed again in the finalizer JVM thread. The second error file is here.
The stack is different but the context is the same (during PAM.dispose()):
j com.sun.jna.NativeLibrary.getSymbolAddress(Ljava/lang/String;)J+24
j com.sun.jna.Function.<init>(Lcom/sun/jna/NativeLibrary;Ljava/lang/String;ILjava/lang/String;)V+68
j com.sun.jna.NativeLibrary.getFunction(Ljava/lang/String;ILjava/lang/String;)Lcom/sun/jna/Function;+59
j com.sun.jna.NativeLibrary.getFunction(Ljava/lang/String;I)Lcom/sun/jna/Function;+7
j com.sun.jna.NativeLibrary.getFunction(Ljava/lang/String;Ljava/lang/reflect/Method;)Lcom/sun/jna/Function;+109
j com.sun.jna.Library$Handler.invoke(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;+203
j com.sun.proxy.$Proxy16.pam_end(Lorg/jvnet/libpam/impl/PAMLibrary$pam_handle_t;I)I+23
j org.jvnet.libpam.PAM.dispose()V+18
j org.jvnet.libpam.PAM.finalize()V+5
Now, the test phase is aborted because it is not a stable component.
Did you encounter same issues during development?
I hope this helps : I found a JVM crash issue at JNA (java-native-access/jna#24)
If you need furhter details do not hesitate to write me.
It is taking almost 3 seconds to succeed or fail the authentication, which is quite slow.
Caused by: java.lang.UnsatisfiedLinkError: /tmp/jna/jna2123156991551141605.tmp: /lib64/libc.so.6: version `GLIBC_2.11' not found (required by /tmp/jna/jna2123156991551141605.tmp)
Hi, I attempted to use libpam4j 1.7 (jna 3.5.0) on a Centos 5.8 x86_64, with glibc2.5 installed, but received the "GLIBC_2.11" not found error. The same code worked on a Centos 5.5 x86 (32bit) with glibc2.5.
I downgraded to libpam4j 1.5 (jna 3.2.2), and the problem went away (but was still present in 1.6 with jna 3.3.0).
I believe this is a JNA issue. I saw a Jenkins bug report of the same problem, where the solution seemed to have been a rebuilt JNA: https://issues.jenkins-ci.org/browse/JENKINS-10354?actionOrder=asc
I wanted to report that downgrading to libpam4j 1.5 fixed it, however.
The libpam4j authenticate() function does not seem to work on the recently released CentOS/RHEL8, at least in a docker container.
See below to reproduce. Maybe some PAM configuration requires changes or something needs to be installed for the PAM functionality used by libpam4j to work on centos 8?
/**
* This simple test program does not work on centos:8, at least in a docker container.
* It has been working on centos:6 and centos:7.6.1810 Any idea what changed in centos
* maybe some configuration is needed to enable something libpam4 relied on?
*
# SETUP:
* Download libpam4j and JNA jars:
* http://mvnrepository.com/artifact/org.kohsuke/libpam4j
* https://github.com/twall/jna
* $ docker run -ti centos:8 bash
yum install -y passwd # already installed on centos:7.6.1810
yum install -y java-11-openjdk-devel passwd # same behavior with java-8,
curl -fLO https://repo1.maven.org/maven2/net/java/dev/jna/jna/5.4.0/jna-5.4.0.jar # this newer version didn't help
curl -fLO https://repo1.maven.org/maven2/net/java/dev/jna/jna/4.5.2/jna-4.5.2.jar
curl -fLO https://repo1.maven.org/maven2/org/kohsuke/libpam4j/1.11/libpam4j-1.11.jar
useradd -p password gw-john # -p does not seem to work
passwd gw-john # enter "password" twice
* BUILD:
javac -classpath ./jna-4.5.2.jar:./libpam4j-1.11.jar:. PamHello.java
* RUN:
java -classpath ./jna-4.5.2.jar:./libpam4j-1.11.jar:. PamHello gw-john password
* ERROR on centos8:
Exception: org.jvnet.libpam.PAMException: pam_acct_mgmt failed : Authentication failure
org.jvnet.libpam.PAMException: pam_acct_mgmt failed : Authentication failure
at org.jvnet.libpam.PAM.check(PAM.java:110)
at org.jvnet.libpam.PAM.authenticate(PAM.java:131)
at PamHello.main(PamHello.java:40)
*/
import org.jvnet.libpam.PAM;
import org.jvnet.libpam.UnixUser;
public class PamHello {
public static void main(String[] argv) {
if (argv.length != 2) {
System.out.println("Run: 'PamHello username password' to test libpam4j authentication: " + argv.length);
System.exit(1);
}
try {
PAM pam = new PAM("login");
UnixUser u = pam.authenticate(argv[0], argv[1]);
System.out.println("User " + u.getUserName() + " " + u.getUID() + " " + u.getGID() + " " + u.getDir() + " " + u.getGecos() + " " + u.getShell() + " in " + u.getGroups());
} catch (Exception e) {
System.out.println("Exception: " + e);
e.printStackTrace();
System.exit(1);
}
System.exit(0);
}
}
Currently, the call to pam_acct_mgmt is commented out in PAM.authenticate. Thus any login restrictions configured via PAM account modules are ignored by PAM.authenticate.
This usually affects, among others, settings in /etc/security/access.conf (pam_access), /etc/nologin (pam_nologin) and host/service name authorization of pam_ldap.
Any return value other than PAM_SUCCESS from pam_acct_mgmt should prevent a successful authentication.
The method UnixUser.getUserName() returns the same string that was pass in the method PAM.authenticate(). That the writing depends from the input. Expected is the right writing of the USER from pamlib.
A possible fix can be to replace the line:
return new UnixUser(userName,pwd);
with:
return new UnixUser(pwd.getPwName(),pwd);
Hi!
I'm trying to make use of this library within Spring Security. It's been awesomely easy.
One issue I've run into is that UnixUser's final class modifier makes it so I can mock it via Mockito. This makes it so I essentially can't test my code's use of the library without having access to an actual pam service.
Any chance you could make it non-final?
When I run the test program https://gist.github.com/jamshid/8776435 (written for another bug) I get inconsistent results from getGroups() and sometimes some corruption in the getShell() result. Tested on CentOS 6.5 and Ubuntu 13.
I added the user gw-john with:
# groupadd gw-admin
# useradd gw-john --groups gw-admin -M
# echo gw-john:password | chpasswd
The program starts 1000 threads doing PAM.authenticate() and outputs the user's info, but many of the results do not list the gw-admin group and there's even some garbage (seen on Ubuntu 13). Btw I usually get the inconsistent groups even with 10 threads.
Any ideas? I guess I should try a non-java version to see if it's reproducible.
$ sudo java -classpath ./jna-3.5.2.jar:./libpam4j-1.7.jar:. PamTest 1000 | grep User | sort | uniq
User gw-john 1001 1004 /home/gw-john /bin/sh in [gw-admin]
User gw-john 1001 1004 /home/gw-john /bin/sh in [gw-admin, gw-john]
User gw-john 1001 1004 /home/gw-john /bin/sh in [gw-john]
User gw-john 1001 1004 /home/gw-john /bin/sh in [operatorx, gw-john]
User gw-john 1001 1004 /home/gw-john /dbus:/bise/shvar/lib/gnats/bin/sh in [gw-admin, gw-john]
Hi,
Out of curiosity, I tried libpam4j on several Linux distro. It worked well on all of them, except Debian 5.0 (which is not really a recent OS). The stacktrace I got is:
JNA: Callback org.jvnet.libpam.PAM$1@6aad0302 threw the following exception:
java.lang.ExceptionInInitializerError
at java.lang.Class.initializeClass(libgcj.so.90)
at org.jvnet.libpam.PAM$1.callback(PAM.java:80)
at java.lang.reflect.Method.invoke(libgcj.so.90)
at com.sun.jna.CallbackReference$DefaultCallbackProxy.invokeCallback(CallbackReference.java:471)
at com.sun.jna.CallbackReference$DefaultCallbackProxy.callback(CallbackReference.java:501)
at com.sun.jna.Function.invoke(Function.java:383)
at com.sun.jna.Function.invoke(Function.java:315)
at com.sun.jna.Library$Handler.invoke(Library.java:212)
at $Proxy0.pam_authenticate(Unknown Source:0)
at org.jvnet.libpam.PAM.authenticate(PAM.java:124)
at Main.main(Main.java:19)
Caused by: java.lang.IllegalArgumentException: incompatible return types: public abstract org.jvnet.libpam.impl.LinuxPasswd org.jvnet.libpam.impl.LinuxCLibrary.getpwnam(java.lang.String), public abstract org.jvnet.libpam.impl.CLibrary$passwd org.jvnet.libpam.impl.CLibrary.getpwnam(java.lang.String)
at java.lang.reflect.Proxy$ProxySignature.checkCompatibility(libgcj.so.90)
at java.lang.reflect.Proxy$ProxyData.getProxyData(libgcj.so.90)
at java.lang.reflect.Proxy.getProxyClass(libgcj.so.90)
at java.lang.reflect.Proxy.newProxyInstance(libgcj.so.90)
at com.sun.jna.Native.loadLibrary(Native.java:415)
at com.sun.jna.Native.loadLibrary(Native.java:391)
at org.jvnet.libpam.impl.CLibrary$Instance.init(CLibrary.java:143)
at org.jvnet.libpam.impl.CLibrary$Instance.access$000(CLibrary.java:134)
at org.jvnet.libpam.impl.CLibrary.<clinit>(CLibrary.java:132)
at java.lang.Class.initializeClass(libgcj.so.90)
...10 more
I looked for the definition of struct passwd
on Debian 5, and according to the manpage, it is the same as described in LinuxPasswd.java.
By curiosity, what would it take to add Debian 5 support?
I'm very new to PAM and JNA, so I would like to know if I can consider doing it if needed in the future.
Thanks!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.