bin/112574: sshd(8) ignores nologin(5) if using PAM and public key

Yar Tikhiy yar at comp.chem.msu.su
Tue Jun 5 10:10:15 UTC 2007


The following reply was made to PR bin/112574; it has been noted by GNATS.

From: Yar Tikhiy <yar at comp.chem.msu.su>
To: des at freebsd.org
Cc: bug-followup at freebsd.org
Subject: Re: bin/112574: sshd(8) ignores nologin(5) if using PAM and public key
Date: Tue, 5 Jun 2007 14:03:08 +0400

 Hi Dag-Erling,
 
 What do you think about the following patch for pam_nologin?
 
 It addresses two problems described in PR bin/107612 and PR bin/112574.
 First, it adds full support for login.conf(5) so that "nologin" and
 "ignorenologin" capabilities are respected for the current user.
 Second, it adds an account management function identical to the
 authentication one so that pam_nologin can always work for sshd.
 Besides, it adds more error checking to pam_nologin.
 
 By adding account management function to pam_nologin, it also opens
 pam_nologin for use in services that do implicit authentication,
 such as cron and atrun.
 
 Thanks!
 
 -- 
 Yar
 
 --- //depot/vendor/freebsd/src/lib/libpam/modules/pam_nologin/pam_nologin.8	2001/08/26 18:40:31
 +++ //depot/user/yar/hack/lib/libpam/modules/pam_nologin/pam_nologin.8	2007/05/23 10:30:24
 @@ -24,7 +24,7 @@
  .\"
  .\" $FreeBSD: src/lib/libpam/modules/pam_nologin/pam_nologin.8,v 1.5 2001/08/26 18:05:35 markm Exp $
  .\"
 -.Dd July 8, 2001
 +.Dd May 23, 2007
  .Dt PAM_NOLOGIN 8
  .Os
  .Sh NAME
 @@ -39,34 +39,37 @@
  .Sh DESCRIPTION
  The NoLogin authentication service module for PAM,
  .Nm
 -provides functionality for only one PAM category:
 -authentication.
 +provides the same functionality for two PAM categories:
 +authentication and account management.
  In terms of the
  .Ar module-type
 -parameter, this is the
 +parameter, those are the
  .Dq Li auth
 -feature.
 +and
 +.Dq Li account
 +features.
  It also provides a null function for session management.
  .Ss NoLogin Authentication Module
 -The NoLogin authentication component
 -.Pq Fn pam_sm_authenticate ,
 -always returns success for the superuser,
 -and returns success for all other users
 -if the file
 -.Pa /var/run/nologin
 -does not exist.
 -If
 -.Pa /var/run/nologin
 -does exist,
 -then its contents are echoed
 -to non-superusers
 +The NoLogin authentication component,
 +.Fn pam_sm_authenticate ,
 +verifies whether logins are administratively disabled via
 +.Xr nologin 5 .
 +It returns success if the user's login class has an "ignorenologin"
 +capability specified in
 +.Xr login.conf 5
 +or the
 +.Xr nologin 5
 +file does not exist.
 +If neither condition is met,
 +then the contents of
 +.Xr nologin 5
 +are echoed
  before failure is returned.
 -If a "nologin" capability
 -is specified in
 +The location of
 +.Xr nologin 5
 +is specified by a "nologin" capability in
  .Xr login.conf 5 ,
 -then the file thus specified
 -is used instead.
 -This usually defaults to
 +which defaults to
  .Pa /var/run/nologin .
  .Pp
  The following options may be passed to the authentication module:
 @@ -82,6 +85,13 @@
  reasons why the user's
  authentication attempt was declined.
  .El
 +.Ss NoLogin Account Management Module
 +The NoLogin account management component,
 +.Fn pam_sm_acct_mgmt , 
 +returns the same value as the NoLogin authentication component
 +would return.
 +This component can be used to provide the NoLogin functionality
 +to services that skip PAM authentication.
  .Sh SEE ALSO
  .Xr syslog 3 ,
  .Xr login.conf 5 ,
 --- //depot/vendor/freebsd/src/lib/libpam/modules/pam_nologin/pam_nologin.c	2006/03/20 17:37:22
 +++ //depot/user/yar/hack/lib/libpam/modules/pam_nologin/pam_nologin.c	2007/05/23 10:28:55
 @@ -47,23 +47,24 @@
  #include <unistd.h>
  
  #define PAM_SM_AUTH
 +#define PAM_SM_ACCOUNT
  
  #include <security/pam_appl.h>
  #include <security/pam_modules.h>
  #include <security/pam_mod_misc.h>
  
 -#define	NOLOGIN	"/var/run/nologin"
 +#define	_PATH_NOLOGIN	"/var/run/nologin"
  
 -static char nologin_def[] = NOLOGIN;
 +static char nologin_def[] = _PATH_NOLOGIN;
  
 -PAM_EXTERN int
 -pam_sm_authenticate(pam_handle_t *pamh, int flags __unused,
 -    int argc __unused, const char *argv[] __unused)
 +static int
 +pam_nologin_check(pam_handle_t *pamh, int flags)
  {
  	login_cap_t *lc;
  	struct passwd *pwd;
  	struct stat st;
  	int retval, fd;
 +	ssize_t ss;
  	const char *user, *nologin;
  	char *mtmp;
  
 @@ -73,42 +74,70 @@
  
  	PAM_LOG("Got user: %s", user);
  
 -	lc = login_getclass(NULL);
 +	pwd = getpwnam(user);
 +	if (pwd == NULL)
 +		return (PAM_USER_UNKNOWN);
 +
 +	/*
 +	 * login_getpwclass(3) will select the "root" class by default
 +	 * if pwd->pw_uid is 0.  That class should have "ignorenologin"
 +	 * capability so that super-user can bypass nologin.
 +	 */
 +	lc = login_getpwclass(pwd);
 +	if (lc == NULL) {
 +		PAM_LOG("Unable to get login class for user %s", user);
 +		return (PAM_SERVICE_ERR);
 +	}
 +
 +	if (login_getcapbool(lc, "ignorenologin", 0)) {
 +		login_close(lc);
 +		return (PAM_SUCCESS);
 +	}
 +
  	nologin = login_getcapstr(lc, "nologin", nologin_def, nologin_def);
 -	login_close(lc);
 -	lc = NULL;
  
  	fd = open(nologin, O_RDONLY, 0);
 -	if (fd < 0)
 +	if (fd < 0) {
 +		login_close(lc);
  		return (PAM_SUCCESS);
 +	}
  
 -	PAM_LOG("Opened %s file", NOLOGIN);
 +	PAM_LOG("Opened %s file", nologin);
  
 -	pwd = getpwnam(user);
 -	if (pwd && pwd->pw_uid == 0)
 -		retval = PAM_SUCCESS;
 -	else {
 -		if (!pwd)
 -			retval = PAM_USER_UNKNOWN;
 -		else
 -			retval = PAM_AUTH_ERR;
 +	if (fstat(fd, &st) == 0) {
 +		mtmp = malloc(st.st_size + 1);
 +		if (mtmp != NULL) {
 +			ss = read(fd, mtmp, st.st_size);
 +			if (ss > 0) {
 +				mtmp[ss] = '\0';
 +				pam_error(pamh, "%s", mtmp);
 +			}
 +			free(mtmp);
 +		}
  	}
  
 -	if (fstat(fd, &st) < 0)
 -		return (retval);
 +	PAM_VERBOSE_ERROR("Administrator refusing you: %s", nologin);
 +
 +	close(fd);
 +	login_close(lc);
 +
 +	return (PAM_AUTH_ERR);
 +}
 +
 +PAM_EXTERN int
 +pam_sm_authenticate(pam_handle_t *pamh, int flags,
 +    int argc __unused, const char *argv[] __unused)
 +{
  
 -	mtmp = malloc(st.st_size + 1);
 -	if (mtmp != NULL) {
 -		read(fd, mtmp, st.st_size);
 -		mtmp[st.st_size] = '\0';
 -		pam_error(pamh, "%s", mtmp);
 -		free(mtmp);
 -	}
 +	return (pam_nologin_check(pamh, flags));
 +}
  
 -	if (retval != PAM_SUCCESS)
 -		PAM_VERBOSE_ERROR("Administrator refusing you: %s", NOLOGIN);
 +PAM_EXTERN int
 +pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
 +    int argc __unused, const char *argv[] __unused)
 +{
  
 -	return (retval);
 +	return (pam_nologin_check(pamh, flags));
  }
  
  PAM_EXTERN int
 --- //depot/vendor/freebsd/src/etc/pam.d/sshd	2003/04/30 22:38:07
 +++ //depot/user/yar/hack/etc/pam.d/sshd	2007/05/23 10:35:59
 @@ -13,6 +13,7 @@
  auth		required	pam_unix.so		no_warn try_first_pass
  
  # account
 +account		required	pam_nologin.so
  #account 	required	pam_krb5.so
  account		required	pam_login_access.so
  account		required	pam_unix.so


More information about the freebsd-bugs mailing list