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.