I also didn't point this out in my original post, but I fixed a misuse of pam_end(). The status passed to pam_end() should be the returned status of the last PAM library call. This is noted in the documentation for Linux-PAM.