Documentation
¶
Overview ¶
Package pamtester verifies and changes users' login passwords by calling the system's libpam directly via purego (no cgo required).
The core type is Transaction, which corresponds to one PAM transaction (pam_start .. pam_end). Authenticate, AcctMgmt and ChangeAuthTok are its methods. The top-level functions CheckUserPassword and ChangeUserPassword are convenience wrappers around a single transaction.
How it works:
Linux commands like login, su, sudo, and passwd all authenticate passwords
through PAM (Pluggable Authentication Modules). The flow is:
1. pam_start() Opens a PAM transaction and registers a
conversation callback function.
2. pam_authenticate() PAM internally uses modules like pam_unix.so,
which call back into the registered conversation
function to request the password. We supply the
password string to be verified in that callback.
3. pam_acct_mgmt() Checks account validity (expired, locked, ...).
4. pam_end() Closes the transaction.
The actual password comparison (reading /etc/shadow and hashing) is done by
pam_unix.so. Non-root processes can typically verify their own password:
when pam_unix lacks permission to read /etc/shadow directly, it delegates
to the setuid-root unix_chkpwd helper, so this library does not require
root privileges.
Dependencies:
go get github.com/ebitengine/purego
Index ¶
Constants ¶
This section is empty.
Variables ¶
var PamService = "passwd"
PamService is the default PAM service configuration file under /etc/pam.d/, used when Options.Service is empty.
Functions ¶
This section is empty.
Types ¶
type Error ¶
type Error int32
Error is a PAM return code (from <security/_pam_types.h>) as a Go error. Errors returned by this package wrap an Error, so callers can classify failures with errors.Is:
if errors.Is(err, pamtester.ErrAuth) { ... wrong password ... }
const ( ErrOpen Error = 1 // PAM_OPEN_ERR ErrSymbol Error = 2 // PAM_SYMBOL_ERR ErrService Error = 3 // PAM_SERVICE_ERR ErrSystem Error = 4 // PAM_SYSTEM_ERR ErrBuf Error = 5 // PAM_BUF_ERR ErrPermDenied Error = 6 // PAM_PERM_DENIED ErrAuth Error = 7 // PAM_AUTH_ERR — wrong password ErrCredInsufficient Error = 8 // PAM_CRED_INSUFFICIENT ErrUserUnknown Error = 10 // PAM_USER_UNKNOWN ErrMaxTries Error = 11 // PAM_MAXTRIES ErrNewAuthTokReqd Error = 12 // PAM_NEW_AUTHTOK_REQD — password correct but expired, must be changed ErrAcctExpired Error = 13 // PAM_ACCT_EXPIRED ErrSession Error = 14 // PAM_SESSION_ERR ErrCredExpired Error = 16 // PAM_CRED_EXPIRED ErrCred Error = 17 // PAM_CRED_ERR ErrNoModuleData Error = 18 // PAM_NO_MODULE_DATA ErrConv Error = 19 // PAM_CONV_ERR ErrAuthTok Error = 20 // PAM_AUTHTOK_ERR ErrAuthTokRecovery Error = 21 // PAM_AUTHTOK_RECOVERY_ERR — e.g. wrong old password in ChangeAuthTok ErrAuthTokLockBusy Error = 22 // PAM_AUTHTOK_LOCK_BUSY ErrAuthTokDisableAging Error = 23 // PAM_AUTHTOK_DISABLE_AGING ErrTryAgain Error = 24 // PAM_TRY_AGAIN ErrIgnore Error = 25 // PAM_IGNORE ErrAbort Error = 26 // PAM_ABORT ErrAuthTokExpired Error = 27 // PAM_AUTHTOK_EXPIRED ErrModuleUnknown Error = 28 // PAM_MODULE_UNKNOWN ErrBadItem Error = 29 // PAM_BAD_ITEM ErrConvAgain Error = 30 // PAM_CONV_AGAIN ErrIncomplete Error = 31 // PAM_INCOMPLETE )
PAM return codes (Linux-PAM numbering).
type Options ¶
type Options struct {
// Service selects the PAM service file under /etc/pam.d/.
// Empty means the package-level default PamService.
Service string
// RHost, if non-empty, is set as PAM_RHOST — the remote host the request
// originates from. Services performing authentication on behalf of remote
// clients should set this so that modules like pam_faillock/pam_access
// and audit logs record the real source.
RHost string
// TTY, if non-empty, is set as PAM_TTY.
TTY string
// RUser, if non-empty, is set as PAM_RUSER — the requesting user.
RUser string
}
Options carries optional parameters for Start. The zero value is valid.
type Transaction ¶
type Transaction struct {
// contains filtered or unexported fields
}
Transaction represents one PAM transaction, i.e. a pam_start .. pam_end lifetime. Obtain one with Start, and always Close it. A Transaction is safe for sequential use; its methods serialize via an internal mutex.
func Start ¶
func Start(user string, opts *Options) (*Transaction, error)
Start opens a PAM transaction for user. opts may be nil. The caller must Close the returned Transaction.
func (*Transaction) AcctMgmt ¶
func (t *Transaction) AcctMgmt() error
AcctMgmt runs pam_acct_mgmt: it checks that the account is valid — not expired or locked, and access not denied by modules like pam_access or pam_time. A special case is an error matching ErrNewAuthTokReqd: the account is fine but the password has expired and must be changed (e.g. via ChangeAuthTok).
func (*Transaction) Authenticate ¶
func (t *Transaction) Authenticate(password string) error
Authenticate verifies password via pam_authenticate: regardless of what the PAM module asks (typically "Password:"), it responds uniformly with the given password. Returns nil if the password is correct; a wrong password yields an error matching ErrAuth (use errors.Is).
Note that Authenticate only proves the password is right — call AcctMgmt afterwards to check that the account itself is still usable.
func (*Transaction) ChangeAuthTok ¶
func (t *Transaction) ChangeAuthTok(oldPassword, newPassword string) error
ChangeAuthTok changes the user's password via pam_chauthtok. When run without root privileges PAM first asks for the current password ("(current) UNIX password:"), then for the new one twice; as root the old password is usually not requested and oldPassword may be empty.
Prompts containing "new" (case-insensitive) are answered with newPassword, anything else with oldPassword. Go programs never call setlocale(), so libpam prompts stay untranslated C-locale English and this matching is reliable even when LANG is set.
Failures (wrong oldPassword, newPassword rejected by quality checks, or no permission to write /etc/shadow) yield errors matching ErrAuthTok or ErrAuthTokRecovery depending on the module. Note that unlike password verification, actually updating the password requires write access to /etc/shadow: root always works, while non-root only works on systems whose pam_unix ships a setuid unix_update helper (e.g. RHEL; Debian/Ubuntu do not — there the passwd(1) command relies on its own setuid bit).
func (*Transaction) Close ¶
func (t *Transaction) Close() error
Close ends the transaction with pam_end and releases all resources. Calling Close more than once is harmless.
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
pamtester
command
Command pamtester is a small CLI demo that reads a password from stdin and verifies it against the current user's PAM account.
|
Command pamtester is a small CLI demo that reads a password from stdin and verifies it against the current user's PAM account. |