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

bunch of questions: pam_unix implementation... (long)



Hello!

Some time now I spent on implementing pam_unix module...
And have some questions that I can't deal myself.
Some of them are from current pam_unix behavour -- it is questionable;
and some are new.  Here is them all.  And note that I don't ask about
compatibility (except when noted) with current pam_unix implementation
--
in most places I ask about "The Right Thing(tm)".  I'm pretty shure
that almost all current pam_unix behavour should be preserved (again,
except at least places where it is (probably) buggy).


1. How to "reliable" determine if we need a shadow entry, and
if we need special privileges to get it.

In current pam_unix code, it is done by comparing pw_passwd field with
"x" (to mean "plain shadow file") and with "*NP*" (to mean "Nis
Password"),
all other values here means "take this value as a password".
With the second case, [e]uid reset to those of the user before
attempting
to get shadow entry (this is a "special" privileges about I wrote
above).

This scheme hit some questions that are "serious" enouth so I want to
ask here about them.

1.a.  Iff we have another auth methods (LDAP,NIS+ etc), is this set of
"magic" passwd values ("x", "*NP*) sufficient?  Maybe this set should be
extended (e.g. "*LP*" as LDAP passwd, "*NPP*" as nis+ passwd etc), or,
maybe
just some magic character (like *) or "strange" password length should
indicate that condition?  (Condition here: a: password stored elsewhere
and b: to get it, we need to reset [e]uid).

1.b. Why we need to have "special" privileges to get shadow entry stored
somewhere in network, as with nis case?  There is no such concept of
"network
user id", at least local unix uid can't be correated to "network uid".
So, the enforcement from nis client library (to get shadow entry of some
person you should have uid equal to uid of that person) is not
practically
useful, since it is just easy to modify nis client code (compile it by
itself, implement it in perl etc) to avoid such enforcement.
Maybe this enforcement can help in situations where some buggy daemon
has been cracked and hacker attempted to use it to check user's
passwords.
But in this case hacker should just add more code to his crack to avoid
enforcement (since it already able to modify running code of that
daemon,
it is not so hard to implement this).  Anyway, this situation is more
fantastic then real.
This issue is not "very" pam-related, but pam should deal with it.

1.c. It will be nice if we can determine _why_ shadow entry unavailable.
If getspnam() returns NULL, what a cause?  Maybe it just does not
exists,
maybe there are unsufficient privileges to get it (we are not root, or
nis [e]uid issues etc).  Does anybody knows how to do this?  I looked to
glibc source, it seemed to me that "files" implementation of getspXXX()
sets errno=EACCESS in case we are not root (as from fopen()), and we
already
can catch this, without using errno (if we are shure that shadow is in
/etc/shadow), but network implementations are not so nice in this
respect.

And also -- what values in each case should return each pam_unix
entry?  I see three choices -- PAM_AUTHINFO_UNAVAIL,
PAM_CRED_INSUFFICIENT
and PAM_AUTH_ERR.  And think that even suid helper should return
PAM_AUTHINFO_UNAVAIL if it can't find shadow entry (currently pam_unix
returns PAM_AUTH_ERR in this case).

1.d.  The pw_passwd field -- maybe it is sufficient to say where to find
real shadow entry?  Should we search all system databases that we
supports
to find where we should update password?  Or maybe value of password
field
is sufficient?  We already depend on pw_passwd value then getting shadow
entry, and searching all system databases seemed to be at least
inconsistent
with "checking current password" stage.

1.f.  But -- maybe we should just ignore value of pw_passwd and attempts
to get shadow entry and "fall back" to that value if not found?  Without
that setreuid() tricks that anyway should be different for other
databases
that can be supported via nsswitch?  "Funny" idea... ;)

2.  If auth's module flags permits usage of empty (null) passwords, and
password stored _is_ empty.  In this case, current pam_unix module
ignores
any given password -- is just returns PAM_SUCCESS.  But in this case,
especially if some flag such as use_authtok/use_first_pass is set,
PAM_AUTHTOK will contain some password...  So, should we satisfy with
_any_ password here, or with just _empty_ one?  I think that any !=
empty...
If we determined that system password is empty, we can not ask user to
provide password, but if it already provided some password, we should
check
if it is empty...  Maybe I'm not right here?
But wait, there is already one application that can broke if the "right"
behavour will be restored.  It is xlock -- it will not allow to press
"Ok" button untill user fills password field!  So, if user has really
empty
system password, he will be unable to unlock his screen...
Another possibility is to have additional flag for exactly this purpose,
but I think that it should _not_ be implemented -- not so many demand on
having empty passwords this way...

Also around this -- if module flags does not permits usage of null
passwords,
but user has empty password in _encrypted_ form.  In this case, his
password
field will not be empty (e.g. crypt("", "aa") == "aaQSqAReePlq6").
Should we disallow access in this case also, by checking entered
password,
not only stored one?

3.  setuid binary helper.  I see a little demand on this (I was very
curious why it was implemented, untill I found at least one application
that can rely on it -- it is xlock and the like).  Should we really
implement this helper?  Maybe xlock should have it's own helper instead?
And if should:
  it seemed to me that this helper should accept a username entered, and
not
rely on getuid() -- if we have some "users" shared one uid, e.g. for
mail access, this helper should _not_ check "mail owner"'s password,
but mail user's one...  In other words, it should accept username,
and verify if this username have uid equal of those user running the
helper, and _not_ as it does currently (checks password of user
determined
by uid).
  is should be unnecessary to call helper from pam_unix when there is
no password record available (getpwnam() returned NULL) or if uid
returned by getpwnam() does not match our uid returned by getuid(),
isn't it?
DoS attacks for example...

3.a Maybe this helper should be used to change password also?
But in this case I don't know how to avoid it's usage directly, thus
allowing users to have passwords of bad quality -- without e.g.
pam_cracklib...


4. some more-or-less minor questions, "grouped" together.

4.a. why current pam_unix uses "strange" method of "storing" password
afetr a user prompt?  Here is a simplified code:

  pam_converse(..., &resp, ...);
  pass = strdup(resp[0].resp);
  pam_drop_reply(resp);

Why strdup(), and have another possibility to return PAM_BUF_ERROR?
Why not just use:

  pam_converse(..., &resp, ...);
  pass = resp[0].resp; resp[0].resp = NULL;
  pam_drop_reply(resp);

4.b. Is there any way to clear shadow file buffer, and should we clean
it and other shadow (crypted) passwords so carefully?  I see e.g.
`pam_overwrite(salt); salt=NULL' code fragments -- are them necessary
without cleaning up buffers that are used by getspnam() etc?

4.c. Can anyone comment -- does we really need to support "brokencrypt"
(that was a bug with endianess issues) that was discussed in this
list already?

4.d. What's purpose of no_store_pass flag (in this case pam_unix stores
password in "private" module item instead of in PAM_AUTHTOK).  pam_unix
itself does not uses this item.  Maybe data item name should be
configurable?
And maybe pam_unix itself should be able to get authtok from some other
(configurable) item instead of PAM_[OLD]AUTHTOK for {use,try}_first_pass
(at least to be consistent with itself)?

4.e. Counting of unsuccesseful auth attempts in pam_unix seemed to me
also strange.  It stores one counter together with username.  It should
be some demand of doing so, and I just can't find it...  Note that this
approach can be used for implementing some DoS attack -- give many
huge "usernames" -- all will be in memory, and we will have all memory
used, but no "too many attempts" error (I'm not shure here)...
I don't really understand cooperation between pam module and application
here -- in respect of "attepmts" -- for example, pam_cracklib uses it's
own loop attempting to ask new password, but pam_unix does not.
What is the Right Thing and where (i.e. in what pam entry/stack)?

4.f.  bigcrypt() implementation in both pam_pwdb and pam_unix seemed to
be broken.  I don't understand it (just don't looked to it really), but
verified it -- trivial program that calls bigcrypt with two command-line
argument and prints result showed me that "big" prefix in bigcrypt
does nothing -- password with 8 letters crypts the same way as any
longer
password that have same first 8 letters.  I.e. result from bigcrypt
is the same as from plain crypt.  What's happened here!?

4.g. Should we ever support "plain" crypt?  pam_unix have "md5" and
"bigcrypt" options, and by default should use "plain" crypt.  Should
this
behawour be preserved, or that options should be just ignored and "md5"
used always?  This may break some compatibility, so answer probably
"not"
here.  But I can argue against "bigcrypt" option -- it should be noop.

4.h. currently pam_unix always sets PAM_AUTHTOK (or private item) after
asking password _before_ it checking.  It should set this item only
after
_successeful_ checking, and clear it on each unsuccesseful attempt,
isn't it?
And it should clear it if it permits empty pass (see 2. also), isn't it?


----EOQL (End Of Questions List:) ---

This is not final -- I have another Qs, but those will be next time...
;)

Great thanks!

Michael.





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