PAM notes

From Helpful
Revision as of 14:13, 8 October 2019 by Helpful (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search
Security related stuff.

Practical


Theory


Unsorted


These are primarily notes
It won't be complete in any sense.
It exists to contain fragments of useful information.


pam rules

Simple example of a PAM rule file:

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


The columns are:

  • module interface (facility)
  • control flag - controls how rules can short-circuit yes/no answers, avoid doing so, and such
  • module name
  • module arguments - often empty


module interfaces

one of:

  • auth - authentication - requests and verifies the validity of login, e.g. a password
can also set credentials, such as group memberships or Kerberos tickets
  • account - account management, including authorization i.e. verifies that access is allowed - considering e.g. account expiry, time-of-day logic
  • password - authentication token update (often mostly meaning password changes)
  • session - configures/manages user sessions
can e.g. mount a home directory, figure out user mailbox


Few modules take part in all of these. Consider e.g.

  • pam_nologin is only there to deny a specific case, so only need be in auth
  • pam_unix can be used to authenticate, do extra checks, to change password, and affects the session - so plays in all
  • pam_cracklib is used to deny setting bad passwords (e.g. minor variations), so only needs to be in password


See also:


Control field

Conceptually, each line can decide

  • to change what we return (and each line can only return one thing)
  • whether to go on, or stop now


It's actually a little more interesting - PAM builds a stack of state, one for each module - yet most uses are much simpler than what you could do.

The logic allows things like

having distinct modules that can accept authentication,
complex logic, e.g. have elements that get executed in multiple paths

If you don't keep it simple, you may want to draw out a state diagram, to make sure you don't mess up...


Control field:

  • binding
If the module succeeds and no earlier module in the chain has failed, the chain is immediately terminated and the request is granted
If the module fails, the rest of the chain is executed, but the request will ultimately be denied
  • required
If the module succeeds, the rest of the chain is executed, and the request is granted unless some other module fails.
If the module fails, the rest of the chain is still executed, but the request will ultimately be denied.
  • requisite
If the module succeeds, the rest of the chain is executed, and the request is granted unless some other module fails.
If the module fails, the chain is immediately terminated and the request is denied.
  • sufficient
If the module succeeds and no earlier module in the chain has failed, the chain is immediately terminated and the request is granted.
If the module fails, the module is ignored and the rest of the chain is executed.
As the semantics of this flag may be somewhat confusing, especially when it is used for the last module in a chain, it is recommended that the binding control flag be used instead if the implementation supports it.
  • optional
The module is executed, but its result is ignored.
If all modules in a chain are marked optional, all requests will always be granted.
useful when setting environment, hooking in features
  • include - ...lines from another file at this point.
Useful for sharing logic.
But since it acts like 'insert lines here', try to avoid jumps, they can get confusing.
  • substack - like include, but the whole thing is executed as if it were a single module - we get its eventual result.
more precisely, termination within it skips only the rest of the included lines. (and jumps cannot jump out)



The default reaction to a return value is a basic mapping to pass or fail(verify).

You can set your own ruleset with:

[value=action ...]

value is one of:

  • success - module says it's happy
  • ignore - module signals it wants its return value to be ignored
  • abort - module says stop now
  • default - 'all return values not explicitly mentioned in this [set]', often used to catch all errors/failures (because there's a bunch of those)
having this often forces you to mention ignore=ignore (and sometimes other things = some obvious thing), or they would fall under the default action
  • errors/failures include:
open_err, symbol_err, service_err, system_err, buf_err, auth_err, session_err, cred_err, conv_err, authtok_err, authtok_recover_err
user_unknown, perm_denied, cred_insufficient, authinfo_unavail, new_authtok_reqd, authtok_lock_busy, authtok_disable_aging, authtok_expired, acct_expired, maxtries, cred_unavail, cred_expired, try_again, module_unknown, bad_item, conv_again, incomplete, no_module_data


action is one of

  • ignore - module's return status will not contribute to the stack's return code
  • bad - flag ourselves as having failed (doesn't terminate)
  • die - bad, and terminate
  • ok - this module's return code should be considered (...if there are no errors)
  • done - ok, and termination
  • n (an integer ≥1) - ok, and skip the next n rules
  • reset - clear stack module state



Note that the singe-world control fields are essentially shorthands for common cases, of the verbose form explained above.

required
is
[success=ok new_authtok_reqd=ok ignore=ignore default=bad]
requisite
is
[success=ok new_authtok_reqd=ok ignore=ignore default=die]
sufficient
is
[success=done new_authtok_reqd=done default=ignore]
optional
is
[success=ok new_authtok_reqd=ok default=ignore]

Example

This article/section is a stub — probably a pile of half-sorted notes, is not well-checked so may have incorrect bits. (Feel free to ignore, fix, or tell me)


For example:

[success=2 ignore=ignore default=die]</tt>

means:

if the module succeeds, skip the next two lines
ignore=ignore is primarily so that ignore doesn't get swallowed by default
...default triggers on every return value other than success or ignore


Basic login via a unix terminal looks like:

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


If you e.g. use PBIS for authentication via AD, then you can decide you add a fallback source for the additional logins:

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

Notes:

  • success=n means "skip the next n rules", in here skipping past the "deny auth" rule (to the permit rule)
  • nullok_secure means empty passwords are permitted
  • control flags:
requisite for the pam_deny line so that it will unconditionally fail and deny access -- unless this line is not executed at all
  • When you have additional things to be run (non-auth things, e.g. controlling the user's environment), you would often avoid binding and sufficient (in the control field) as they can make things unpredictable.

PAM modules include...

This article/section is a stub — probably a pile of half-sorted notes, is not well-checked so may have incorrect bits. (Feel free to ignore, fix, or tell me)
  • pam_env - read environment variables from a file


  • pam_fprint - fingerprint reader
  • pam_unix - system's auth as configured in /etc/nsswitch.conf (which often just means reading /etc/passwd and /etc/shadow)
  • pam_nologin - when /etc/nologin exists, this denies login from anyone but root.
Used e.g. while booting.
  • pam_securetty - root login to special devices (typically hardware terminals)


  • pam_deny - always denies access. e.g. used after a line that does success=1.
  • pam_permit - always succeeds, and sets the result values with a positive result.
Used to avoid the case where nothing set success (e.g. when using skip rules)
and can avoid some unpredictability from earlier variable sets (verify)
  • pam_rootok - authenticates when the uid is 0
e.g. for su
  • pam_succeed_if
e.g. pam_succeed_if.so user ingroup nopasswdlogin
useful for passwordless guest accounts(verify)


  • pam_krb5 - integrate Kerberos 5
  • pam_access - logdaemon style login access control, via /etc/security/access.conf


  • pam_limits - limit resources, according to /etc/security/limits.conf
  • pam_faildelay - per-application delay on auth failure(verify)
  • pam_cap - set capabilities, according to /etc/security/capability.conf (verify)
see also http://linux.die.net/man/7/capabilities
  • pam_mkhomedir


  • pam_group - /etc/security/group.conf
  • pam_loginuid


  • pam_ecryptfs - for encrypted homedirs, where a passphrase can be unwrapped using the supplied password
  • pam_motd - print message of the day
  • pam_mail - print status of the user's mail
  • pam_mount - mount filesystems at login time (commonly for remote shares)
http://pam-mount.sourceforge.net/pam_mount.8.html


  • pam_keyinit -
  • pam_gnome_keyring -
  • pam_kwallet -
  • pam_selinux -


pam_systemd


for the password facility: pam_pwcheck pam_unix2 pam_make



Various files

debug

To turn on debug for every module:

touch /etc/pam_debug

To turn it on for a specific module, add debug as an argument to it, e.g.

login   auth    required    pam_unix.so debug


There are sometimes specific debug-related arguments, e.g. pam_mysql has
verbose=1

module-specific notes

pam_mount

See also: