I'm not sure where to discuss this, but this seemed like a venue
that would attract some knowledgeable feedback.
I am designing a PAM module to serve as a backup authentication
mechanism for a device when it has lost network connectivity to it's
LDAP server. There is no local password containing file on the
system. The credential used has OTP-ish properties and encodes a
privilege level as well.
Upon successful authentication, I planned on the module fabricating
a one line passwd file that would be timestamped and deleted past usage.
A helper nsslib function will deal with fronting the "user"
information to login and the system.
I was wondering which api service to put the logic the builds the
authenticated user information.
I was thinking that pam_setcred() would be appropriate.
But then I decided to read the login code and my head exploded.
Below is a simplified snippet of the login code we have in our distro.
I looked at the current code on kernel.org, and it seems to be
rewritten and refactored into multiple subroutines, but still has the
same logic flow.
---<snippet of login.c>----
/*
* Grab the user information out of the password file for future usage
* First get the username that we are actually using, though.
*/
retcode = pam_get_item(pamh, PAM_USER, (const void **) &username);
PAM_FAIL_CHECK;
if (!username || !*username) {
fprintf(stderr, _("\nSession setup problem, abort.\n"));
syslog(LOG_ERR, _("NULL user name in %s:%d. Abort."),
__FUNCTION__, __LINE__);
pam_end(pamh, PAM_SYSTEM_ERR);
exit(1);
}
if (!(pwd = getpwnam(username))) {
fprintf(stderr, _("\nSession setup problem, abort.\n"));
syslog(LOG_ERR, _("Invalid user name \"%s\" in %s:%d. Abort."),
username, __FUNCTION__, __LINE__);
pam_end(pamh, PAM_SYSTEM_ERR);
exit(1);
}
/*
* Create a copy of the pwd struct - otherwise it may get
* clobbered by PAM
*/
memcpy(&pwdcopy, pwd, sizeof(*pwd));
pwd = &pwdcopy;
pwd->pw_name = strdup(pwd->pw_name);
pwd->pw_passwd = strdup(pwd->pw_passwd);
pwd->pw_gecos = strdup(pwd->pw_gecos);
pwd->pw_dir = strdup(pwd->pw_dir);
pwd->pw_shell = strdup(pwd->pw_shell);
if (!pwd->pw_name || !pwd->pw_passwd || !pwd->pw_gecos ||
!pwd->pw_dir || !pwd->pw_shell) {
fprintf(stderr, _("login: Out of memory\n"));
syslog(LOG_ERR, "Out of memory");
pam_end(pamh, PAM_SYSTEM_ERR);
exit(1);
}
username = pwd->pw_name;
/*
* Initialize the supplementary group list.
* This should be done before pam_setcred because
* the PAM modules might add groups during pam_setcred.
*/
if (initgroups(username, pwd->pw_gid) < 0) {
syslog(LOG_ERR, "initgroups: %m");
fprintf(stderr, _("\nSession setup problem, abort.\n"));
pam_end(pamh, PAM_SYSTEM_ERR);
exit(1);
}
retcode = pam_open_session(pamh, 0);
PAM_FAIL_CHECK;
retcode = pam_setcred(pamh, PAM_ESTABLISH_CRED);
PAM_FAIL_CHECK;
----<end snippet>----
1) Notice that pam_setcred is called _after_ pam_open_session.
This is direct conflict with the documentation of pam_setcred and
doesn't bode well for any session parameters that might have been
created using context created by setcred.
2) The bigger picture: notice that getpwnam() and initgroups() has
been called before any of this.
So if pam_setcred() or pam_open_session() have any effect on
PAM_USER, the user database, or the information returned by nss
functions they will not be noticed by login.
[the comment about PAM clobblering the pwd info from getpwnam() is
misleading. PAM has no access to data in the program except though
interfaces. But getpwnam() does return a pointer to an internal
static structure, so copying the information out right away is just
good system interface practice.]
Well I can figure out how to work around this, but this just seems
wrong. The PAM interfacing should be completed (setcred,
open_session), before fetching any info on the user. This probably
makes no difference for LDAP users, if the fetched information was
cached and available to nss after authentication time, but screws up
anyone building something slightly more complicated. Perhaps those
that work with this more can see some other issues or explain.
I think, that the calls to PAM should be moved to the beginning of
this snippet, and put in proper order. ... but I'm new in this space.
David Mitton.
_______________________________________________
Pam-list mailing list
Pam-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/pam-list