Hello! 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 /etc/passwd (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 pam_unix) 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 etc 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 explanation: bigcrypt ok, it is not so good as md5, why it ever needed when "plain" crypt() and md5 exists? audit if administrator requested debugging, why it should not see passwords? 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 some strange way uses garbage instead of supplied password when autentificates via pap in ppp (dialout) session. May be I'm wrong here. shadow 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 nis only /etc files are supported, rest are for other modules remember=NNN password quality checking belongs to dedicated module such as pam_cracklib 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 ;) Regards, Michael. ===== 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: debug 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 cleartext. # 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). # silent 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. try_first_pass 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. use_first_pass 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 fail. nullok 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? nonull 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. tries=NNN 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. nodelay do not delay on failed authentification attempt. By default, pam_unix will sleep 3 secounds after each unsuccesseful attempt. delay=NNN 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. not_set_pass 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 PAM_NEW_AUTHTOK_REQD) 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: debug 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. silent 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. Arguments: debug as usual, do some debugging output to syslog silent 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: debug do debugging logging. Note that user's passwords will be shown in system logs if this flag is set! silent show no output to application nullok nonull try_first_pass use_first_pass nodelay delay=NNN 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. md5 use md5 algorithm to encrypt password (by default it is encrypted using system's crypt routine). use_new_pass # 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. not_set_pass 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. minlen=XXX only one "password quality" mechanism implemented in this module is the minimum password length that can be set by this parameter. Default 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 password. When changing a password, module will always compares current password with entered by user to enshure that noone has changed this password while 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 Explanation: First time, when PAM walks this stack with PAM_PRELIM_CHECK flag set (and if there are no other problems present), pam_asknewpass will succed; 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 to this module, also using PAM_[OLD]AUTHTOK only. # The same question again -- Am I understand the scheme right ?! Other ~~~~~ Other options recognized by this module (all stacks) for compatibility: bigcrypt audit use_authtok shadow nis remember=NNN All those are ignored. If any of this option will be used with any stack 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.