Linux-PAM lets an application delegate authentication policy to administrator-controlled modules. The application owns the user interaction and its privilege boundary; PAM owns a transaction handle, loads the configured stack, and combines module results. Consequently, an application can use local passwords, smart cards, directory services, MFA, or account restrictions without embedding those mechanisms.
Transaction Roles #
A PAM transaction has five roles:
- the application starts and ends the transaction;
- the service is the policy name supplied to
pam_start, commonlylogin,sshd, orsudo; - a management group selects the operation:
auth,account,session, orpassword; - a module is a shared object implementing one or more management-group entry points;
- the conversation function lets a module request prompts, informational messages, and responses through the application.
The application begins with pam_start(service, user, &conversation, &pamh). pam_handle_t is opaque and belongs to one transaction; create another handle for another concurrent transaction. A typical authorization path calls pam_authenticate, optionally pam_setcred, then pam_acct_mgmt; it calls pam_open_session before granting a session and pam_close_session while tearing it down. Password changes use pam_chauthtok. Regardless of the path, the application calls pam_end(pamh, last_status), which invalidates the handle and runs registered cleanup callbacks.
pam_handle_t *pamh = NULL;
int status = pam_start("example", user, &conversation, &pamh);
if (status == PAM_SUCCESS)
status = pam_authenticate(pamh, 0);
if (status == PAM_SUCCESS)
status = pam_acct_mgmt(pamh, 0);
if (pamh != NULL)
pam_end(pamh, status);auth establishes identity and may establish credentials. account checks whether access is currently allowed, including expiry and policy restrictions. session performs lifecycle work such as audit setup, limits, or mounts. password updates an authentication token. An authentication success without the appropriate account and session calls is not a complete login flow.
Policy Files and Stacks #
Linux-PAM reads /etc/pam.d/SERVICE when the directory exists; otherwise it uses /etc/pam.conf. /etc/pam.d policy overrides a same-named vendor file in /usr/lib/pam.d. A pam.conf rule includes a service field, while a file under pam.d obtains its service name from the filename:
service type control module-path arguments
example auth required pam_unix.so try_first_passThe four simple controls define result flow:
requiredrecords failure but evaluates the rest of the stack;requisitefails immediately;sufficientsucceeds immediately when no earlier required module failed, while its failure is ignored;optionalmatters only when it is the only effective module in the stack.
Extended controls, such as [success=1 default=bad], map specific PAM_* returns to actions including ignore, bad, die, ok, done, reset, and a numeric jump. They are not decoration: changing a jump or a default action can bypass a factor or turn a service outage into authorization.
include inserts rules of the requested management type from another policy file. substack also evaluates another file, but done, die, and jumps are contained within that substack. Module arguments are module-specific; preserve quoting and avoid assuming an option accepted by one module is meaningful to another.
Writing Modules Safely #
Modules implement group-specific symbols such as pam_sm_authenticate, pam_sm_acct_mgmt, pam_sm_open_session, and pam_sm_chauthtok. Obtain the user with pam_get_user and authentication tokens with pam_get_authtok instead of creating a competing prompt. Store transaction-scoped state through pam_set_data, supply a cleanup callback, and report diagnostics through pam_syslog without logging passwords, tokens, or secret-derived material.
Return the documented PAM_* result that represents the failure. Do not collapse an unavailable directory, an invalid password, and an internal error into an accidental success. Module code executes in security-sensitive and sometimes privileged processes, so validate every external input, avoid unsafe environment assumptions, use bounded memory handling, and make cleanup idempotent.
Test policy changes with a dedicated service name and account first. Keep an existing root console or recovery path authenticated by known-good policy, validate syntax before installation, and test both success and each expected failure path. Editing the policy used by a remote administrative session without a recovery path can lock out every administrator.
The Linux-PAM application manual, especially pam_start(3), pam_end(3), and pam.conf(5), is the authoritative interface for Linux-PAM behavior.
Comments
Read or comment on GitHub (sign-in required to comment)