1

I have these lines in /etc/pam.d/sshd:

# PAM configuration for the Secure Shell service

# Standard Un*x authentication.
@include common-auth

# Disallow non-root logins when /etc/nologin exists.
account    required     pam_nologin.so

# Uncomment and edit /etc/security/access.conf if you need to set complex
# access limits that are hard to express in sshd_config.
# account  required     pam_access.so

# Standard Un*x authorization.
@include common-account

# SELinux needs to be the first session rule.  This ensures that any
# lingering context has been cleared.  Without this it is possible that a
# module could execute code in the wrong domain.
session [success=ok ignore=ignore module_unknown=ignore default=bad]        pam_selinux.so close

# Set the loginuid process attribute.
session    required     pam_loginuid.so

# Create a new session keyring.
session    optional     pam_keyinit.so force revoke

# Standard Un*x session setup and teardown.
@include common-session

# Print the message of the day upon successful login.
# This includes a dynamically generated part from /run/motd.dynamic
# and a static (admin-editable) part from /etc/motd.
session    optional     pam_motd.so  motd=/run/motd.dynamic
session    optional     pam_motd.so noupdate

# Print the status of the user's mailbox upon successful login.
session    optional     pam_mail.so standard noenv # [1]

# Set up user limits from /etc/security/limits.conf.
session    required     pam_limits.so

# Read environment variables from /etc/environment and
# /etc/security/pam_env.conf.
session    required     pam_env.so # [1]
# In Debian 4.0 (etch), locale-related environment variables were moved to
# /etc/default/locale, so read that as well.
session    required     pam_env.so user_readenv=1 envfile=/etc/default/locale

# SELinux needs to intervene at login time to ensure that the process starts
# in the proper default security context.  Only sessions which are intended
# to run in the user's context should be run after this.
session [success=ok ignore=ignore module_unknown=ignore default=bad]        pam_selinux.so open

# Standard Un*x password updating.
@include common-password

Now I installed google-authenticator and appended auth required /usr/local/lib/security/pam_google_authenticator.so authtok_prompt=TOTP? to the end of that file. Now it works, but if I entered a incorrect password, the authentication will fail immediately, without asking for OTP.

What I want is that if either one entered is incorrect, the system still prompt for another one, then output Access Denied (No prompt which one is wrong).

According to the documentation above, has the OTP module and pam_unix.so set as required should do the job. But seems like on my system the pam_unix.so is inside another file (@include common-password). Here is the content of that file:

#
# /etc/pam.d/common-password - password-related modules common to all services
#
# This file is included from other service-specific PAM config files,
# and should contain a list of modules that define the services to be
# used to change user passwords.  The default is pam_unix.

# Explanation of pam_unix options:
#
# The "sha512" option enables salted SHA512 passwords.  Without this option,
# the default is Unix crypt.  Prior releases used the option "md5".
#
# The "obscure" option replaces the old `OBSCURE_CHECKS_ENAB' option in
# login.defs.
#
# See the pam_unix manpage for other options.

# As of pam 1.0.1-6, this file is managed by pam-auth-update by default.
# To take advantage of this, it is recommended that you configure any
# local modules either before or after the default block, and use
# pam-auth-update to manage selection of other modules.  See
# pam-auth-update(8) for details.

# here are the per-package modules (the "Primary" block)
password        [success=1 default=ignore]      pam_unix.so obscure sha512
# here's the fallback if no module succeeds
password        requisite                       pam_deny.so
# prime the stack with a positive return value if there isn't one already;
# this avoids us returning an error just because nothing sets a success code
# since the modules above will each just jump around
password        required                        pam_permit.so
# and here are more per-package modules (the "Additional" block)
# end of pam-auth-update config

I don't know whether I should modify this file because seems like other file still depends on it and I only want the OTP module to work in SSH sessions. What should I modify? Any help is appreciated.

1
  • The password PAM module deals with password change, auth deals with authentication. Can you include common-auth instead of common-password in the question? Dec 25, 2019 at 10:06

1 Answer 1

2

You probably have in your common-auth the following lines:

auth    [success=1 default=ignore]  pam_unix.so nullok_secure
auth    requisite                   pam_deny.so
auth    required                    pam_permit.so

In case of password failure in pam_unix, PAM will go to the next line, which is an unconditional failure and is requisite so the authentication stops here. In case of correct authentication the second line will be skipped.

You probably want to replace the @include common-auth with:

auth    required    pam_unix.so nullok_secure
auth    required    /usr/local/lib/security/pam_google_authenticator.so authtok_prompt=TOTP?

and add some other modules from common-auth (pam_cap.so?).

2
  • The common-auth file looks exactly like the one above except for the try_first_pass part. Tried your solution and it worked like a charm! Thanks!
    – whc2001
    Dec 25, 2019 at 22:17
  • 1
    The try_first_pass means: try the password provided to a previous authentication module. In the case it obviously makes no sense, so I edited the answer. Dec 25, 2019 at 22:28

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .