|
You're joking, but I'm 100% serious. PAM is crusty and has a bad architecture. The fact that it's written in C, and is linked into another program as a library makes it impossible to fully isolate it from its host application, and exposes it to a myriad possible exploit points. Even wrapper binaries are not a great idea because of how UNIX works. fork() + exec() means the executed binary inherits a lot of state from the caller. Open files, signals, environment variables, chroot, mlock, resource limits, seccomp... there's a myriad of mechanisms that an executed binary can be exposed to, and even if it somehow perfectly takes all of them into account and defends itself against any possible malicious manipulation, the next kernel version could add a new one. That's why I think a sane, modern version of PAM should be a service and only communicate via a UNIX socket. That way you vastly reduce the attack surface, and allow locking up the PAM bits into their own, well defended box. |
The calling convention is C, but you can write PAM in any language.
"and is linked into another program as a library makes it impossible to fully isolate it from its host application"
Huh? You can never isolate the client side code. You will always have something in your app.
"I think a sane, modern version of PAM should be a service and only communicate via a UNIX socket."
So, write a module that talks to a socket. That's how like half of the PAM modules already operate. You will always have to have code in the application to talk to whatever oracle you're using. What you're describing here isn't any different from how PAM already works.