[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

2nd Qs: proposed description of new pam_unix


First of all, great thanks for your attention and answers/suggestions
to my previous "bunch of questions" here.

And let me try once more time, I hope that it will be last one. :)
Pam_unix is essential pam module, so I just have no rights to decide
if it is "right" only myself.

Here is a proposed README file for new pam_unix module, with
more-or-less complete description of operations, that should be
a base for all documentation in release of this module.   It
contains some comments (marked as usual by placing a hash sign
as the first character in the line) about places that is not
"well-known" to me and that possible needs some additional attention.

All issues in short in one place:

o algorithm used to determine if we should lookup a shadow entry
  and if we need (re)se uid for this (for NIS+ etc) -- it is
  implemented the same as pam_unix currently have, until we will
  have a better solution

o we always logs entered username (even if user may have (mis)typed
  his password instead of username -- we can't determine this)

o nullok and nonull semantics: nullok will permit login without
  prompting a password (actually, _any_ password can be used)
  if user's password (or shadow) entry is empty.  Nonull will not
  permit the usage of empty password, even if it matches the crypted
  one stored in system.  There is a minor defference in this --
  two options are not opposite of each other.  Moreother, them
  can be used simultaneously :)

o pam has a flag (PAM_DISALLOW_NULL_AUTHTOK) -- what should be done
  with it and with nullok/nonull options -- it is not clear to me.

o suid binary helper should accept username as argument -- I still
  think that it should use getpwnam() instead of getpwuid().  Thus,
  it will not be compatible with current pam_unix implementation.

o new proposed options to session stack: utmp, wtmp and lastlog,
  as I think that them belongs to pam_unix as module name says
  (things specific to unix ;).  Session stack in pam_unix currently
  just empty (except of two syslog calls).  And some details about
  this ones (them are just planned -- when I finish/polish other stuff).

o option for passwd stack to _not_ to ask _new_ password and get it
  from pam item.  {use,try}_first_pass is not sutable here (them
  both used in the same stack also), use_authtok is not so consistent
  in other modules as the first two.  I use `use_new_pass' here
  for this purpose, and this may be wrong thing to do

o pam_unix will only try to change password in /etc/shadow and
  (and it will ignore `shadow' flag), and not in other places.
  Instead there should be other set of pam_passwd_XXX "changers",
  with pam_passwd_files and pam_passwd_nisplus (that I want to write
  also, them are trivial here, and ..._files shares code with my
  Ok, supporting only one place allowed to wrote code that is far
  more clean and easy than for many (and for two also) places, and
  I think that this win is enouth to drop support for other services :)
  Seriously, I think that in _most_ cases no network-aware things
  should be ever tried (only when them really used), and introducing
  nis support in pam_unix will require additional library dependances

o it is not clear to me if I understand PAM_PRELIM_CHECK/PAM_UPDATE
  logic correctly.  I verify (possible ask) the current password then
  first flag set, and change (and possible ask) the new password then
  second is set (current pam_unix does the same).  Is this a right
  think to do to ask current password in prelim_check?  If not, then
  we have troubles stacking modules

o flags that was removed but exists in current pam_unix, and

    ok, it is not so good as md5, why it ever needed when "plain"
    and md5 exists?
    if administrator requested debugging, why it should not see
    The biggest trouble when debugging will be needed is then _password_
    entered incorrectly, not the other things (well, sometimes username
    also but less frequently).  One example -- my windoze machine in
    strange way uses garbage instead of supplied password when
    autentificates via pap in ppp (dialout) session.
    May be I'm wrong here.
    It was used only in passwd stack.  Since files is only one storage
    that new pam_unix supports (there is nis also in current pam_unix),
    and since new module will authomatically determine if shadow or
    plain password file should be used, this is unnecessary
    only /etc files are supported, rest are for other modules
    password quality checking belongs to dedicated module such as

o I don't know why `likeauth' (undocumented) option needed.
  Why just not have corresponding entry point in module?
  I currently implemented it, but not shure why :)

o if some flag used for inappropriate stack (but valid in other),
  or if one of removed flags used, warning is logged (in the first
  case, current pam_unix is quiet)

o retry option is not used in password stack, max tries is always
  1 here, so that module will return PAM_MAXTRIES (is this good?)
  if second attempt will be tried

And there will be nice if someone can comment on _completness_ in
features.  Supplied readme contains enouth information (I hope)
to see what this module does.

Thanks in participation and attention
(way, this is again a long reading -- sorry me bad ;)


===== cut

This is the (proposed) readme file for pam_unix module, with only
general information omitted.

auth stack

The trickest part of auth process used in pam_unix is the
attempt to (reliable) determine if user's password stored
outside of user info (available via getpwnam()), and if it
should use getspnam() to get this info (i.e. if system uses
shadow password _for particular user_), and, also, what
rights should be needed to get this shadow entry.  Currently,
pam_unix assumes that:

  o if passwd field returned by getpwnam() has value "*NP*",
    then user's password info actually is in shadow, and
    to access it, module should have uid equal to the user
    to be autentificated (NIS+ requires that caller process
    should have uid = user to get those user's shadow entry).
    In this case, pam_unix tries to set "correct" user id
    and issues a call to getspnam().
  o if passwd field returned by getpwnam() has one-letter "x"
    value, then there should be a shadow entry, and to access
    it, one need to use getspnam() directly.
  o overwise, the password stored directly in structure returned
    by getpwnam(), in crypted form.

# Ok, this is the hardest question that still here.
# For now, things implemented this way -- while there
# is no other, better solution.
# One little note on this: maybe we should try just "plain"
# getspnam() even if the pw_passwd's value is "*NP*", and
# only after this should try to (re)set uid and try again.

pam_unix's auth module accepts the following arguments:

  do some debugging via syslog.  Module will show a lot more
  information when it is operates than usual.  Note that with
  this flag set, there is a potential ability exists to see
  user supplied password in clear text in system logs.
  (btw, if user just enters his password instead of username,
  that password will _always_ be logged by the module).
  Note that this option should not be used in production
  environment, since it will generate a lot of info in system
  log, and since this info can contain user's passwords in
# There are some comments in current pam_unix about possibility
# for the user to type his password instead of username, and
# about carefulness while logging username.  I don't think
# this is useful -- we need to log username that was tried in
# any case -- if we will not log it, we will lost the ability
# to track some attacks.
# audit option is removed (implemented in current pam_unix).

  Be "silent", i.e. do not produce any output.  In this case,
  module will not send any messages to the application, including
  warnings etc.  This option has no effect on logging.

  if some previous module has asked used's password, then try it
  first to see if it match the system password.  If it does not
  match, or there is no password previously entered/asked, then
  module will ask it again.  In the latter case a warning will
  be logged.

  Do not ask user about his password, use previously entered
  and set (by other module) one.  If that password is unavailable
  or does not match the system password, autentification will

  if system's password field is emptu (null) then permit any password,
  including empty (note that pam_unix really permits _any_ password
  in this case).  pam_unix will not ask user's password if this
  option is set _and_ system's password field is empty.
  Note also that if system's password field contained crypted form
  of empty password, module will not notice this and will prompt
  user's password anyway.
  By default, pam_unix does not allow users with empty password
  field to authentificate.
# There is a flag in PAM to set the _opposite_ internanally
# (PAM_DISALLOW_NULL_AUTHTOK).  So, maybe this (nullok) option
# should be the default?  If so, why we ever need this?

  disallow empty password.  If user's password is empty, access
  will be denied.  This applies to both empty password field in
  system database _and_ to crypted empty string as a password.
  Note that this is not a exact opposite of nullok flag, but
  difference is very minor.

 retry=NNN (compat?)
  maximum number of tries to perform authentification, default is 3.
  Module will ask password no more than this times, and if user
  will not supply a valid password, it will be denied access.
  Module uses private data item to count unsuccesseful attempts.

  do not delay on failed authentification attempt.  By default,
  pam_unix will sleep 3 secounds after each unsuccesseful attempt.

  gives a delay, in secounds, to issue after each unsuccesseful
  authentification attempt.  Setting this to 0 is equivalent to
  setting nodelay flag.  Default is 3 sec.

  Module will not store password in PAM item.  I don't know any
  practical usage of this flag, and it can be removed in the future.

With shadow password system, pam_unix can be used with uid=0
(or whatether rights needed to access shadow entry, e.g. on
some systems there is a group `shadow', and /etc/shadow is
readable by that group); this is a "normal" mode of operation.
Or, alternatively, it can be used to verify user's own password
(when current uid != 0).  One practical example of this are
programs like xlock that need to verify user's password to
unlock the screen.  To be able to verify password of a user
and to allow xlock _not_ to be installed suid-root (or sgid-shadow),
pam_unix uses it's own tiny suid-root wrapper (that is typically
installed as /sbin/unix_chkpwd).  If pam_unix is unable to access
to user's shadow entry, it calls that wrapper and passes
username and entered password to it for verification.
Note that this helper will only verify password for user
those uid equal to uid of current process.
# I still don't know if I should pass username to this helper
# or not.  I think that I should, others said that no.
# If no, then current pam_unix's unix_chkpwd can be used;
# If yes, then there will be really little set of situations
# where this can be useful (one example: mailbox system that
# stores all mails using the same uid and also uses system
# user's database to verify user's passwords, and in this case
# will be one uid shared between many usernames (that have no other
# access to this machine) -- mail program itself should run using
# this same uid).

If some accounts have passwords stored in a place that is unaccessible
to getspnam() (and thus to pam_unix), there should be other modules
to verify password.  Example of such stacking:

 auth sufficient pam_unix
 auth sufficient pam_custom1 try_first_pass
 auth sufficient pam_custom2 try_first_pass
 auth required pam_deny

With this, (pam_customN are some custom "password verification" modules)
pam_unix will ask a password and try to verify it.  It all is
ok, authentification process will succed.  Else, first custom
module will be called, that will try to verify already asked password,
than second and so on, while one will return success or while
we comes to the end where access will be denied.  Note that
this scheme allows to use "plain old" shadow file to be used first
to allow e.g. root to log in even there is a network failure and
second modules will fail due to this.
Also, other modules can ask their own passwords (or use different
concept instead of password).

In case of failure, module will just return the error.
Application should repeat the attempt if it wishes to do so, but
should stop if pam returned PAM_MAXTRIES.

account stack

account stack of pam_unix just checks the password aging information.
It only works if there is a shadow entry available for that user.
The algorithm used to retrieve this shadow entry is the same as
for auth stack (module will return success if the shadow entry is
not used, i.e., currently, when password field in structure returned
by getpwnam() does not equal to "x" and "*NP*").

Age checks that will be performed by this module are (see man shadow):

 o password expire date (sp_expire) is less than current date --
   account will not be allowed with code PAM_ACCT_EXPIRED
 o password was not changed after sp_inact days after it should
   be changed (now > last change (sp_lstchg) + sp_max + sp_inact) --
   account will not be allowed with code PAM_ACCT_EXPIRED
 o last change date (sp_lstchg) set to 0 (usually by administrator
   to force user to change password) -- account will be allowed with
   requiring immediately changing password (with code
 o ls last password change date was less than now - min change period
   (sp_min) -- the same as above
 o if the maximum days between password change coming soon (sp_warn),
   module will issue a warning (unless silent flag is set)
   and permits access

This are standard unix password enforcement policies I belive.

No more additional functions will be performed by this module.
Note that account stack can't be used by non-privileged process,
unlike auth stack (i.e. it requires that shadow entry is available
if used).

Options recognized by this module:

  show some more debugging information.  It is not so critical
  option as debug in auth stack, since account stack have no
  deal with user's password, it only uses password aging information.

  do not out any messages (normally pam_unix informs user about
  (possible) password expiration)

session stack

The purpose of this stack in pam_unix is really a logging
facility only.  Normally module logs two lines to syslog
when session started and ended.


  as usual, do some debugging output to syslog

  do say nothing to the user

 utmp (planned)
  record user's session into system's utmp database
  so that commands like `who' will show it.
  Fail if unable to update utmp file.
# I think that this really belongs to pam_unix -- it
# is very "unix way".

 wtmp (planned)
  record user's session in system's wtmp database,
  so that commands like `last' will show it.
  Fail if unable to update utmp file.

 lastlog (planned)
  update last login information (usually in
  /var/log/lastlog) and display last login time
  to user (unless silent flag also given)

 acct (planned)
  do all of utmp, wtmp and lastlog.

# also considered/planned:
#  [uw]tmp_file=/some/path, lastlog_file=/some/path
# Or maybe better:
#  utmp to use standard system utmp file
#  utmp=/some/path to use named file instead
# (i.e. if option has argument after equal sign, treat it
# as filename, overwise use system default filename)

# Some comments about this all:
Comments for [uw]tmp work.  We should open /var/log/wtmp
and /var/state/utmp files in open_session and close them
only in close_session, so that changing uids and chroot
will not affect this.  But in this case we need to have
max of four filedescriptors opened (some systems uses four
files, together with "x" versions (utmpx), like solaris) --
them can be closed by application (typical usage:
  for (i = 3; i < 1024; ++i) close(i);
), this can do bad things with application (that is not
expected to have open files except of 0,1,2), and application
can just damage that files (since it is at user control).
In the other way, if we will reopen files at close_session,
them can be unavailable (as I said -- chroot, or non-root)
Both ways are not good.  Maybe fork a separate process for
this?  We can do just fork(), or can fork+exec another little
(non-suid) helper.  Note that in forked process we should
close some files that can be opened by application, e.g.
if it has some pipes opened.

Note that in most cases when logging to wtmp/utmp/lastlog
requested, process calling this module should have uid=0,
or else it will no rights to write that information (there
may be other less restrictive requiriments, such as then
all that files writeable by some group etc).

passwd stack

Unlike other stacks implemented by this module, passwd
stack is not as general, and present here mostly for
compatibility.  It is recommended to use pam_passwd_XXX
# to be written ;)
modules in passwd stack.  Name service switch does not
provide a way to _store_ things -- it is only to retrieve
ones.  Pam_unix implements changing of password stored
only in files in /etc (/etc/passwd, /etc/shadow) and nothing
more.  This module will prompt current password and verifies
it (unless told overwise), prompts for a new password twice
(also unless told overwise) and attempts to change password
in /etc/passwd or /etc/shadow.  It has only very limited
built-in checks for new password "quality" -- one need to
use other modules (such as pam_cracklib) for new password
prompting if he wants that users chooses good passwords.

The algorithm used to verify current password is the same
as in auth stack, except of that this module also checks
password expiration info that is normally (and more complete)
checked in account stack.  Also, suid binary helper does not
used in this stack, so that if shadow entry used but unavailable,
module will not authentificate user.

Arguments for this module:

  do debugging logging.  Note that user's passwords will be
  shown in system logs if this flag is set!

  show no output to application

  the same meaning as for auth stack.  Used when verifying current
  password.  Note that passwd stack will not use tries=NNN parameter,
  it will allow only one try to verify password.

 enforce_root (proposed)
  ask current password and verify it's expiration even if current uid=0.
  Normally module will not ask current password in this case.

  use md5 algorithm to encrypt password (by default it is encrypted
  using system's crypt routine).

# Can anyone suggest a better name for this?
# Maybe use_authtok?  It is not clear to me how this one used in other
# modules, probably there is a lot of confusion with it.
  used in password changing -- use new password available in PAM_AUTHTOK
  PAM item, and do not prompt for new one.  This is not the same as
  {try,use}_first_pass: latter is for verifiyng _current_ password,
  while this option is for asquiring _new_ password.
  If this flag is set, module will not check new password's validity
  (it will ignore minlen parameter and will not compare old and new
  passwords) and will fail if PAM_AUTHTOK is not set.

  as for the auth stack, I don't see usage of this option.
  If given, module will not set PAM_[OLD]AUTHTOK PAM item but
  stores tokens (PAM_AUTHTOK and PAM_OLDAUTHTOK) in private data
  items instead.

  only one "password quality" mechanism implemented in this module is
  the minimum password length that can be set by this parameter. 
  value is 6.
  Also module will refuse to "change" password to the same one.
  Note that if use_new_pass flag set, both this checks will be omitted.

When changing password, module looks if the user have a shadow entry,
by searching /etc/shadow first and when (if not found) looking to
plain passwd entry in /etc/passwd trying to change password there.
# This is not consistent with auth stack.  Probably I should first
# check if passwd entry (from getpwnam()) equals to "x" and attempts
# to open shadow only if it is; and should try to open
# /etc/passwd file if passwd != "*NP*" (well, does not contains "*").

Module will never allow to set password without proper current password
verification (exception to this is if current uid = 0).

Module will lock the passwd/shadow file while it updates information,
but _not_ when it verifies user's current password or asks for a new
one.  This is to avoid long period of lock when user enters his
When changing a password, module will always compares current password
with entered by user to enshure that noone has changed this password
user entered a new one.

Current password prompting will be done if PAM_PRELIM_CHECK flag is
set only.  When PAM_UPDATE flag set (pam calls this module second
time), it also verifies PAM_AUTHTOK (or private data item) to verify
current password.
# Am I understand PAM_PRELIM_CHECK and PAM_UPDATE right here?

Example of stacking this module together with custom "prompter"
(pam_asknewpass) and other password updaters:

  passwd required pam_asknewpass
  passwd sufficient pam_unix use_new_pass
  passwd required pam_custom1 use_first_pass use_new_pass

First time, when PAM walks this stack with PAM_PRELIM_CHECK flag set
(and if there are no other problems present), pam_asknewpass will
after this pam_unix will prompt and verify user's password; it can fail
here if password stored in place known to pam_custom1 module -- in this
case pam_custom will verify it.  In any way, old (current) password
will be stored as a PAM_OLDAUTHTOK item.
Second time then modules called with PAM_UPDATE flag set, pam_asknewpass
will prompt for a new password (and store it in PAM_AUTHTOK); and
pam_unix will try to change it (using PAM_OLDAUTHTOK (it is always
used here and no prompts at this second stage) and PAM_AUTHTOK, due to
use_new_pass flag), and will return success if change is ok; overwise,
pam_custom1 will be invoked that will change password in a place known
this module, also using PAM_[OLD]AUTHTOK only.
# The same question again -- Am I understand the scheme right ?!


Other options recognized by this module (all stacks) for compatibility:


All those are ignored.  If any of this option will be used with any
in pam_unix, warning will be logged.

Warning will be logged also for any valid pam_unix option that is
unappropriate for particular stack.

Any other option will be ignored and error will be logged.

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index] []