diff --git a/Linux-PAM-1.3.1.tar.xz b/Linux-PAM-1.3.1.tar.xz new file mode 100644 index 0000000000000000000000000000000000000000..424ac57beb925a2cd9f02e79911d6d92087b4cae Binary files /dev/null and b/Linux-PAM-1.3.1.tar.xz differ diff --git a/Linux-PAM-1.3.1.tar.xz.asc b/Linux-PAM-1.3.1.tar.xz.asc new file mode 100644 index 0000000000000000000000000000000000000000..7057c1810b583b07d156dd62769bf0d1a705bc6d --- /dev/null +++ b/Linux-PAM-1.3.1.tar.xz.asc @@ -0,0 +1,7 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v2 + +iD8DBQBa/r62bRp/BS5ZJLsRArnKAJ9pGaJHpsEsbOVa5dBQLHYC4DhPuACeJNrg ++DaNc8W13E4Z2ZEUSsgUGe4= +=aSTW +-----END PGP SIGNATURE----- diff --git a/README.md b/README.md deleted file mode 100644 index 0d17adb58cdce73b36255049f95bbb1cbfc90bf2..0000000000000000000000000000000000000000 --- a/README.md +++ /dev/null @@ -1,39 +0,0 @@ -# pam - -#### 介绍 -{**以下是码云平台说明,您可以替换此简介** -码云是 OSCHINA 推出的基于 Git 的代码托管平台(同时支持 SVN)。专为开发者提供稳定、高效、安全的云端软件开发协作平台 -无论是个人、团队、或是企业,都能够用码云实现代码托管、项目管理、协作开发。企业项目请看 [https://gitee.com/enterprises](https://gitee.com/enterprises)} - -#### 软件架构 -软件架构说明 - - -#### 安装教程 - -1. xxxx -2. xxxx -3. xxxx - -#### 使用说明 - -1. xxxx -2. xxxx -3. xxxx - -#### 参与贡献 - -1. Fork 本仓库 -2. 新建 Feat_xxx 分支 -3. 提交代码 -4. 新建 Pull Request - - -#### 码云特技 - -1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md -2. 码云官方博客 [blog.gitee.com](https://blog.gitee.com) -3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解码云上的优秀开源项目 -4. [GVP](https://gitee.com/gvp) 全称是码云最有价值开源项目,是码云综合评定出的优秀开源项目 -5. 码云官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) -6. 码云封面人物是一档用来展示码云会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) diff --git a/bugfix-pam-1.1.8-faillock-failmessages.patch b/bugfix-pam-1.1.8-faillock-failmessages.patch new file mode 100644 index 0000000000000000000000000000000000000000..763ba986fea1f35c5c4dc17d7f155f5e884b1b6e --- /dev/null +++ b/bugfix-pam-1.1.8-faillock-failmessages.patch @@ -0,0 +1,17 @@ +diff --git a/modules/pam_faillock/pam_faillock.c b/modules/pam_faillock/pam_faillock.c +index 1742542..8153638 100644 +--- a/modules/pam_faillock/pam_faillock.c ++++ b/modules/pam_faillock/pam_faillock.c +@@ -445,11 +445,10 @@ faillock_message(pam_handle_t *pamh, struct options *opts) + } + + if (left > 0) { +- left = (left + 59)/60; /* minutes */ + + pam_info(pamh, _("Account temporarily locked due to %d failed logins"), + opts->failures); +- pam_info(pamh, _("(%d minutes left to unlock)"), (int)left); ++ pam_info(pamh, _("(%d seconds left to unlock)"), (int)left); + } + else { + pam_info(pamh, _("Account locked due to %d failed logins"), diff --git a/bugfix-pam-1.1.8-faillock-systemtime.patch b/bugfix-pam-1.1.8-faillock-systemtime.patch new file mode 100644 index 0000000000000000000000000000000000000000..d072f475c4fa98795f320c23f6e1481eb2ed46c0 --- /dev/null +++ b/bugfix-pam-1.1.8-faillock-systemtime.patch @@ -0,0 +1,60 @@ +diff --git a/modules/pam_faillock/pam_faillock.c b/modules/pam_faillock/pam_faillock.c +index 8153638..d71e781 100644 +--- a/modules/pam_faillock/pam_faillock.c ++++ b/modules/pam_faillock/pam_faillock.c +@@ -84,6 +84,7 @@ struct options { + uid_t uid; + int is_admin; + uint64_t now; ++ int time_jumped; + }; + + static void +@@ -98,6 +99,7 @@ args_parse(pam_handle_t *pamh, int argc, const char **argv, + opts->fail_interval = 900; + opts->unlock_time = 600; + opts->root_unlock_time = MAX_TIME_INTERVAL+1; ++ opts->time_jumped = 0; + + for (i = 0; i < argc; ++i) { + +@@ -266,8 +268,6 @@ check_tally(pam_handle_t *pamh, struct options *opts, struct tally_data *tallies + latest_time = tallies->records[i].time; + } + +- opts->latest_time = latest_time; +- + failures = 0; + for(i = 0; i < tallies->count; i++) { + if ((tallies->records[i].status & TALLY_STATUS_VALID) && +@@ -278,6 +278,19 @@ check_tally(pam_handle_t *pamh, struct options *opts, struct tally_data *tallies + + opts->failures = failures; + ++ if (latest_time > opts->now) { ++ pam_syslog(pamh, LOG_WARNING, "system time jumped about %ld seconds.", (latest_time - opts->now)); ++ latest_time = opts->now; ++ opts->time_jumped = 1; ++ ++ for(i = 0; i < tallies->count; i++) { ++ if (tallies->records[i].status & TALLY_STATUS_VALID) ++ tallies->records[i].time = latest_time; ++ } ++ } ++ ++ opts->latest_time = latest_time; ++ + if (opts->deny && failures >= opts->deny) { + if ((!opts->is_admin && opts->unlock_time && latest_time + opts->unlock_time < opts->now) || + (opts->is_admin && opts->root_unlock_time && latest_time + opts->root_unlock_time < opts->now)) { +@@ -508,6 +521,10 @@ pam_sm_authenticate(pam_handle_t *pamh, int flags, + rv = PAM_IGNORE; /* this return value should be ignored */ + write_tally(pamh, &opts, &tallies, &fd); + } ++ if (opts.time_jumped) { ++ if (update_tally(fd, &tallies) != 0) ++ rv = PAM_IGNORE; ++ } + break; + } + diff --git a/bugfix-pam-1.1.8-mod-chinese-date-format.patch b/bugfix-pam-1.1.8-mod-chinese-date-format.patch new file mode 100644 index 0000000000000000000000000000000000000000..fab3dff3a0bb76af7ca761a03fccfa513fe0eea2 --- /dev/null +++ b/bugfix-pam-1.1.8-mod-chinese-date-format.patch @@ -0,0 +1,29 @@ +diff --git a/po/zh_CN.po b/po/zh_CN.po +index 33c257d..2ae6e50 100644 +--- a/po/zh_CN.po ++++ b/po/zh_CN.po +@@ -285,7 +285,7 @@ msgstr "%s 失败:未知的状态 0x%x" + #. TRANSLATORS: "strftime options for date of last login" + #: modules/pam_lastlog/pam_lastlog.c:282 modules/pam_lastlog/pam_lastlog.c:496 + msgid " %a %b %e %H:%M:%S %Z %Y" +-msgstr "%a %b %e %H:%M:%S %Z %Y" ++msgstr "%Y年 %b %e日 %H:%M:%S 星期%a %Z" + + #. TRANSLATORS: " from " + #: modules/pam_lastlog/pam_lastlog.c:291 modules/pam_lastlog/pam_lastlog.c:505 +@@ -320,13 +320,13 @@ msgstr "最后一次失败的登录:%s%s%s" + msgid "There was %d failed login attempt since the last successful login." + msgid_plural "" + "There were %d failed login attempts since the last successful login." +-msgstr[0] "最有一次成功登录后有 %d 次失败的登录尝试。" ++msgstr[0] "最近一次成功登录后有 %d 次失败的登录尝试。" + + #. TRANSLATORS: only used if dngettext is not supported + #: modules/pam_lastlog/pam_lastlog.c:548 + #, c-format + msgid "There were %d failed login attempts since the last successful login." +-msgstr "最有一次成功登录后有 %d 次失败的登录尝试。" ++msgstr "最近一次成功登录后有 %d 次失败的登录尝试。" + + #: modules/pam_limits/pam_limits.c:1091 + #, c-format diff --git a/bugfix-pam-1.1.8-translation-missing-add.patch b/bugfix-pam-1.1.8-translation-missing-add.patch new file mode 100644 index 0000000000000000000000000000000000000000..e356ea90d0c36942ae5fcd9c508cda267ae0e487 --- /dev/null +++ b/bugfix-pam-1.1.8-translation-missing-add.patch @@ -0,0 +1,16 @@ +diff --git a/po/zh_CN.po b/po/zh_CN.po +index 2ae6e50..17eb79e 100644 +--- a/po/zh_CN.po ++++ b/po/zh_CN.po +@@ -572,3 +572,11 @@ msgstr "为 %s 更改 STRESS 密码。" + #: modules/pam_unix/pam_unix_passwd.c:722 + msgid "You must wait longer to change your password" + msgstr "您必须等待更长时间以更改密码" ++ ++#: modules/pam_faillock/pam_faillock.c:447 ++msgid "Account temporarily locked due to %d failed logins" ++msgstr "账户由于%d次登录失败而暂时锁定" ++ ++#: modules/pam_faillock/pam_faillock.c:449 ++msgid "(%d seconds left to unlock)" ++msgstr "%d 秒后解锁" diff --git a/config-util.5 b/config-util.5 new file mode 100644 index 0000000000000000000000000000000000000000..17d7f8add3ac27943fd5ec6f642330005080aa76 --- /dev/null +++ b/config-util.5 @@ -0,0 +1,36 @@ +.TH SYSTEM-AUTH 5 "2006 Feb 3" "Red Hat" "Linux-PAM Manual" +.SH NAME + +config-util \- Common PAM configuration file for configuration utilities + +.SH SYNOPSIS +.B /etc/pam.d/config-util +.sp 2 +.SH DESCRIPTION + +The purpose of this configuration file is to provide common +configuration file for all configuration utilities which must be run +from the supervisor account and use the userhelper wrapper application. + +.sp +The +.BR config-util +configuration file is included from all individual configuration +files of such utilities with the help of the +.BR include +directive. +There are not usually any other modules in the individual configuration +files of these utilities. + +.sp +It is possible for example to modify duration of the validity of the +authentication timestamp there. See +.BR pam_timestamp(8) +for details. + +.SH BUGS +.sp 2 +None known. + +.SH "SEE ALSO" +pam(8), config-util(5), pam_timestamp(8) diff --git a/config-util.pamd b/config-util.pamd new file mode 100644 index 0000000000000000000000000000000000000000..8e70d9aba1dafe593e08f673aac6d03f63d0a428 --- /dev/null +++ b/config-util.pamd @@ -0,0 +1,8 @@ +#%PAM-1.0 +auth sufficient pam_rootok.so +auth sufficient pam_timestamp.so +auth include system-auth +account required pam_permit.so +session required pam_permit.so +session optional pam_xauth.so +session optional pam_timestamp.so diff --git a/fingerprint-auth.pamd b/fingerprint-auth.pamd new file mode 100644 index 0000000000000000000000000000000000000000..604b95ff14ca56eeecaa623be471f2b89efb6a08 --- /dev/null +++ b/fingerprint-auth.pamd @@ -0,0 +1,19 @@ +#%PAM-1.0 +# This file is auto-generated. +# User changes will be destroyed the next time authconfig is run. +auth required pam_env.so +auth sufficient pam_fprintd.so +auth required pam_deny.so + +account required pam_unix.so +account sufficient pam_localuser.so +account sufficient pam_succeed_if.so uid < 500 quiet +account required pam_permit.so + +password required pam_deny.so + +session optional pam_keyinit.so revoke +session required pam_limits.so +-session optional pam_systemd.so +session [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid +session required pam_unix.so diff --git a/gpl-2.0.txt b/gpl-2.0.txt new file mode 100644 index 0000000000000000000000000000000000000000..d159169d1050894d3ea3b98e1c965c4058208fe1 --- /dev/null +++ b/gpl-2.0.txt @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/other.pamd b/other.pamd new file mode 100644 index 0000000000000000000000000000000000000000..c286c823c3f3f8d53f08d26d14e9b8a367b67067 --- /dev/null +++ b/other.pamd @@ -0,0 +1,5 @@ +#%PAM-1.0 +auth required pam_deny.so +account required pam_deny.so +password required pam_deny.so +session required pam_deny.so diff --git a/pam-1.1.0-notally.patch b/pam-1.1.0-notally.patch new file mode 100644 index 0000000000000000000000000000000000000000..9188422d0e24bc692ba4c21cfae19aa166fe4bf6 --- /dev/null +++ b/pam-1.1.0-notally.patch @@ -0,0 +1,24 @@ +From: openEuler Buildteam +Date: Sat, 14 Sep 2019 17:37:36 +0800 +Subject: [PATCH] unsupport pam_tally + +--- + modules/Makefile.am | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/modules/Makefile.am b/modules/Makefile.am +index 0c80cea..4847759 100644 +--- a/modules/Makefile.am ++++ b/modules/Makefile.am +@@ -9,7 +9,7 @@ SUBDIRS = pam_access pam_cracklib pam_debug pam_deny pam_echo \ + pam_mkhomedir pam_motd pam_namespace pam_nologin \ + pam_permit pam_pwhistory pam_rhosts pam_rootok pam_securetty \ + pam_selinux pam_sepermit pam_shells pam_stress \ +- pam_succeed_if pam_tally pam_tally2 pam_time pam_timestamp \ ++ pam_succeed_if pam_tally2 pam_time pam_timestamp \ + pam_tty_audit pam_umask \ + pam_unix pam_userdb pam_warn pam_wheel pam_xauth + +-- +2.19.1 + diff --git a/pam-1.1.3-nouserenv.patch b/pam-1.1.3-nouserenv.patch new file mode 100644 index 0000000000000000000000000000000000000000..f3a742c8d2cc11608a0cf842dd178fae6516519c --- /dev/null +++ b/pam-1.1.3-nouserenv.patch @@ -0,0 +1,27 @@ +diff -up pam/modules/pam_env/pam_env.c.nouserenv pam/modules/pam_env/pam_env.c +--- pam/modules/pam_env/pam_env.c.nouserenv 2010-10-20 09:59:30.000000000 +0200 ++++ pam/modules/pam_env/pam_env.c 2010-11-01 14:42:01.000000000 +0100 +@@ -10,7 +10,7 @@ + #define DEFAULT_READ_ENVFILE 1 + + #define DEFAULT_USER_ENVFILE ".pam_environment" +-#define DEFAULT_USER_READ_ENVFILE 1 ++#define DEFAULT_USER_READ_ENVFILE 0 + + #include "config.h" + +diff -up pam/modules/pam_env/pam_env.8.xml.nouserenv pam/modules/pam_env/pam_env.8.xml +--- pam/modules/pam_env/pam_env.8.xml.nouserenv 2010-10-20 09:59:30.000000000 +0200 ++++ pam/modules/pam_env/pam_env.8.xml 2010-11-01 14:42:01.000000000 +0100 +@@ -147,7 +147,10 @@ + + + Turns on or off the reading of the user specific environment +- file. 0 is off, 1 is on. By default this option is on. ++ file. 0 is off, 1 is on. By default this option is off as user ++ supplied environment variables in the PAM environment could affect ++ behavior of subsequent modules in the stack without the consent ++ of the system administrator. + + + diff --git a/pam-1.1.6-limits-user.patch b/pam-1.1.6-limits-user.patch new file mode 100644 index 0000000000000000000000000000000000000000..3c17b781a205faaffbe144f314b3f14d4b0e3e07 --- /dev/null +++ b/pam-1.1.6-limits-user.patch @@ -0,0 +1,20 @@ +diff -up Linux-PAM-1.1.6/modules/pam_limits/limits.conf.limits Linux-PAM-1.1.6/modules/pam_limits/limits.conf +--- Linux-PAM-1.1.6/modules/pam_limits/limits.conf.limits 2012-08-15 13:08:43.000000000 +0200 ++++ Linux-PAM-1.1.6/modules/pam_limits/limits.conf 2013-03-14 16:43:37.615087671 +0100 +@@ -1,5 +1,16 @@ + # /etc/security/limits.conf + # ++#This file sets the resource limits for the users logged in via PAM. ++#It does not affect resource limits of the system services. ++# ++#Also note that configuration files in /etc/security/limits.d directory, ++#which are read in alphabetical order, override the settings in this ++#file in case the domain is the same or more specific. ++#That means for example that setting a limit for wildcard domain here ++#can be overriden with a wildcard setting in a config file in the ++#subdirectory, but a user specific setting here can be overriden only ++#with a user specific setting in the subdirectory. ++# + #Each line describes a limit for a user in the form: + # + # diff --git a/pam-1.1.8-audit-user-mgmt.patch b/pam-1.1.8-audit-user-mgmt.patch new file mode 100644 index 0000000000000000000000000000000000000000..277a5699f3ce04436235aa498f26f963fc328156 --- /dev/null +++ b/pam-1.1.8-audit-user-mgmt.patch @@ -0,0 +1,31 @@ +diff -up Linux-PAM-1.1.8/modules/pam_tally2/pam_tally2.c.audit-user-mgmt Linux-PAM-1.1.8/modules/pam_tally2/pam_tally2.c +--- Linux-PAM-1.1.8/modules/pam_tally2/pam_tally2.c.audit-user-mgmt 2013-06-18 16:11:21.000000000 +0200 ++++ Linux-PAM-1.1.8/modules/pam_tally2/pam_tally2.c 2014-10-17 12:09:12.965490940 +0200 +@@ -997,9 +997,9 @@ main( int argc UNUSED, char **argv ) + #ifdef HAVE_LIBAUDIT + char buf[64]; + int audit_fd = audit_open(); +- snprintf(buf, sizeof(buf), "pam_tally2 uid=%u reset=%hu", uid, cline_reset); +- audit_log_user_message(audit_fd, AUDIT_USER_ACCT, +- buf, NULL, NULL, ttyname(STDIN_FILENO), 1); ++ snprintf(buf, sizeof(buf), "pam_tally2 reset=%hu", cline_reset); ++ audit_log_acct_message(audit_fd, AUDIT_USER_MGMT, NULL, ++ buf, NULL, uid, NULL, NULL, ttyname(STDIN_FILENO), 1); + if (audit_fd >=0) + close(audit_fd); + #endif +@@ -1040,11 +1040,10 @@ main( int argc UNUSED, char **argv ) + } + else if ( !cline_reset ) { + #ifdef HAVE_LIBAUDIT +- char buf[64]; + int audit_fd = audit_open(); +- snprintf(buf, sizeof(buf), "pam_tally2 uid=all reset=0"); +- audit_log_user_message(audit_fd, AUDIT_USER_ACCT, +- buf, NULL, NULL, ttyname(STDIN_FILENO), 1); ++ audit_log_acct_message(audit_fd, AUDIT_USER_MGMT, NULL, ++ "pam_tally2-reset-all-accts reset=0", "*", -1, ++ NULL, NULL, ttyname(STDIN_FILENO), 1); + if (audit_fd >=0) + close(audit_fd); + #endif diff --git a/pam-1.1.8-full-relro.patch b/pam-1.1.8-full-relro.patch new file mode 100644 index 0000000000000000000000000000000000000000..b2d8526f9df79b80d5dc74242dc826e34e83127a --- /dev/null +++ b/pam-1.1.8-full-relro.patch @@ -0,0 +1,67 @@ +diff -up Linux-PAM-1.1.8/modules/pam_filter/upperLOWER/Makefile.am.relro Linux-PAM-1.1.8/modules/pam_filter/upperLOWER/Makefile.am +--- Linux-PAM-1.1.8/modules/pam_filter/upperLOWER/Makefile.am.relro 2014-09-10 17:17:20.273401344 +0200 ++++ Linux-PAM-1.1.8/modules/pam_filter/upperLOWER/Makefile.am 2014-09-10 17:17:07.857115369 +0200 +@@ -9,7 +9,7 @@ securelibfilterdir = $(SECUREDIR)/pam_fi + + AM_CFLAGS = -I$(top_srcdir)/libpam/include -I$(top_srcdir)/libpamc/include \ + -I$(srcdir)/.. @PIE_CFLAGS@ +-AM_LDFLAGS = @PIE_LDFLAGS@ ++AM_LDFLAGS = -Wl,-z,now @PIE_LDFLAGS@ + LDADD = $(top_builddir)/libpam/libpam.la + + securelibfilter_PROGRAMS = upperLOWER +diff -up Linux-PAM-1.1.8/modules/pam_mkhomedir/Makefile.am.relro Linux-PAM-1.1.8/modules/pam_mkhomedir/Makefile.am +--- Linux-PAM-1.1.8/modules/pam_mkhomedir/Makefile.am.relro 2013-06-18 16:11:21.000000000 +0200 ++++ Linux-PAM-1.1.8/modules/pam_mkhomedir/Makefile.am 2014-09-10 17:18:42.922304935 +0200 +@@ -30,6 +30,8 @@ endif + + sbin_PROGRAMS = mkhomedir_helper + mkhomedir_helper_SOURCES = mkhomedir_helper.c ++mkhomedir_helper_CFLAGS = $(AM_CFLAGS) @PIE_CFLAGS@ ++mkhomedir_helper_LDFLAGS = -Wl,-z,now @PIE_LDFLAGS@ + mkhomedir_helper_LDADD = $(top_builddir)/libpam/libpam.la + + if ENABLE_REGENERATE_MAN +diff -up Linux-PAM-1.1.8/modules/pam_tally2/Makefile.am.relro Linux-PAM-1.1.8/modules/pam_tally2/Makefile.am +--- Linux-PAM-1.1.8/modules/pam_tally2/Makefile.am.relro 2013-06-18 16:11:21.000000000 +0200 ++++ Linux-PAM-1.1.8/modules/pam_tally2/Makefile.am 2014-09-10 17:22:04.339944040 +0200 +@@ -26,6 +26,8 @@ if HAVE_VERSIONING + pam_tally2_la_LDFLAGS += -Wl,--version-script=$(srcdir)/../modules.map + endif + ++pam_tally2_CFLAGS = $(AM_CFLAGS) @PIE_CFLAGS@ ++pam_tally2_LDFLAGS = -Wl,-z,now @PIE_LDFLAGS@ + pam_tally2_LDADD = $(top_builddir)/libpam/libpam.la $(LIBAUDIT) + + securelib_LTLIBRARIES = pam_tally2.la +diff -up Linux-PAM-1.1.8/modules/pam_timestamp/Makefile.am.relro Linux-PAM-1.1.8/modules/pam_timestamp/Makefile.am +--- Linux-PAM-1.1.8/modules/pam_timestamp/Makefile.am.relro 2013-06-18 16:11:21.000000000 +0200 ++++ Linux-PAM-1.1.8/modules/pam_timestamp/Makefile.am 2014-08-13 16:02:49.906688139 +0200 +@@ -36,7 +36,7 @@ pam_timestamp_la_CFLAGS = $(AM_CFLAGS) + pam_timestamp_check_SOURCES = pam_timestamp_check.c + pam_timestamp_check_CFLAGS = $(AM_CFLAGS) @PIE_CFLAGS@ + pam_timestamp_check_LDADD = $(top_builddir)/libpam/libpam.la +-pam_timestamp_check_LDFLAGS = @PIE_LDFLAGS@ ++pam_timestamp_check_LDFLAGS = -Wl,-z,now @PIE_LDFLAGS@ + + hmacfile_SOURCES = hmacfile.c hmacsha1.c sha1.c + hmacfile_LDADD = $(top_builddir)/libpam/libpam.la +diff -up Linux-PAM-1.1.8/modules/pam_unix/Makefile.am.relro Linux-PAM-1.1.8/modules/pam_unix/Makefile.am +--- Linux-PAM-1.1.8/modules/pam_unix/Makefile.am.relro 2013-06-18 16:11:21.000000000 +0200 ++++ Linux-PAM-1.1.8/modules/pam_unix/Makefile.am 2014-08-13 16:02:49.906688139 +0200 +@@ -55,13 +55,13 @@ bigcrypt_LDADD = @LIBCRYPT@ + unix_chkpwd_SOURCES = unix_chkpwd.c md5_good.c md5_broken.c bigcrypt.c \ + passverify.c + unix_chkpwd_CFLAGS = $(AM_CFLAGS) @PIE_CFLAGS@ -DHELPER_COMPILE=\"unix_chkpwd\" +-unix_chkpwd_LDFLAGS = @PIE_LDFLAGS@ ++unix_chkpwd_LDFLAGS = -Wl,-z,now @PIE_LDFLAGS@ + unix_chkpwd_LDADD = @LIBCRYPT@ @LIBSELINUX@ @LIBAUDIT@ + + unix_update_SOURCES = unix_update.c md5_good.c md5_broken.c bigcrypt.c \ + passverify.c + unix_update_CFLAGS = $(AM_CFLAGS) @PIE_CFLAGS@ -DHELPER_COMPILE=\"unix_update\" +-unix_update_LDFLAGS = @PIE_LDFLAGS@ ++unix_update_LDFLAGS = -Wl,-z,now @PIE_LDFLAGS@ + unix_update_LDADD = @LIBCRYPT@ @LIBSELINUX@ + + if ENABLE_REGENERATE_MAN diff --git a/pam-1.2.0-unix-no-fallback.patch b/pam-1.2.0-unix-no-fallback.patch new file mode 100644 index 0000000000000000000000000000000000000000..6295da77caa572ddce7485d6417fe48dc0a57c66 --- /dev/null +++ b/pam-1.2.0-unix-no-fallback.patch @@ -0,0 +1,73 @@ +diff -up Linux-PAM-1.2.0/modules/pam_unix/pam_unix.8.xml.no-fallback Linux-PAM-1.2.0/modules/pam_unix/pam_unix.8.xml +--- Linux-PAM-1.2.0/modules/pam_unix/pam_unix.8.xml.no-fallback 2015-04-27 16:38:03.000000000 +0200 ++++ Linux-PAM-1.2.0/modules/pam_unix/pam_unix.8.xml 2015-05-15 15:54:21.524440864 +0200 +@@ -284,11 +284,10 @@ + + + When a user changes their password next, +- encrypt it with the SHA256 algorithm. If the +- SHA256 algorithm is not known to the ++ encrypt it with the SHA256 algorithm. The ++ SHA256 algorithm must be supported by the + crypt3 +- function, +- fall back to MD5. ++ function. + + + +@@ -299,11 +298,10 @@ + + + When a user changes their password next, +- encrypt it with the SHA512 algorithm. If the +- SHA512 algorithm is not known to the ++ encrypt it with the SHA512 algorithm. The ++ SHA512 algorithm must be supported by the + crypt3 +- function, +- fall back to MD5. ++ function. + + + +@@ -314,11 +312,10 @@ + + + When a user changes their password next, +- encrypt it with the blowfish algorithm. If the +- blowfish algorithm is not known to the ++ encrypt it with the blowfish algorithm. The ++ blowfish algorithm must be supported by the + crypt3 +- function, +- fall back to MD5. ++ function. + + + +diff -up Linux-PAM-1.2.0/modules/pam_unix/passverify.c.no-fallback Linux-PAM-1.2.0/modules/pam_unix/passverify.c +--- Linux-PAM-1.2.0/modules/pam_unix/passverify.c.no-fallback 2015-05-15 15:54:21.525440887 +0200 ++++ Linux-PAM-1.2.0/modules/pam_unix/passverify.c 2015-05-15 15:57:23.138613273 +0200 +@@ -437,10 +437,9 @@ PAMH_ARG_DECL(char * create_password_has + sp = crypt(password, salt); + #endif + if (!sp || strncmp(algoid, sp, strlen(algoid)) != 0) { +- /* libxcrypt/libc doesn't know the algorithm, use MD5 */ ++ /* libxcrypt/libc doesn't know the algorithm, error out */ + pam_syslog(pamh, LOG_ERR, +- "Algo %s not supported by the crypto backend, " +- "falling back to MD5\n", ++ "Algo %s not supported by the crypto backend.\n", + on(UNIX_BLOWFISH_PASS, ctrl) ? "blowfish" : + on(UNIX_SHA256_PASS, ctrl) ? "sha256" : + on(UNIX_SHA512_PASS, ctrl) ? "sha512" : algoid); +@@ -450,7 +449,7 @@ PAMH_ARG_DECL(char * create_password_has + #ifdef HAVE_CRYPT_R + free(cdata); + #endif +- return crypt_md5_wrapper(password); ++ return NULL; + } + sp = x_strdup(sp); + #ifdef HAVE_CRYPT_R diff --git a/pam-1.2.1-faillock-admin-group.patch b/pam-1.2.1-faillock-admin-group.patch new file mode 100644 index 0000000000000000000000000000000000000000..8bd13841ef141bec841d1fce34c03f93cb6466ea --- /dev/null +++ b/pam-1.2.1-faillock-admin-group.patch @@ -0,0 +1,133 @@ +diff -up Linux-PAM-1.3.0/modules/pam_faillock/pam_faillock.c.admin-group Linux-PAM-1.3.0/modules/pam_faillock/pam_faillock.c +--- Linux-PAM-1.3.0/modules/pam_faillock/pam_faillock.c.admin-group 2016-04-04 16:37:38.696260359 +0200 ++++ Linux-PAM-1.3.0/modules/pam_faillock/pam_faillock.c 2017-08-21 16:40:01.624706864 +0200 +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2010 Tomas Mraz ++ * Copyright (c) 2010, 2017 Tomas Mraz + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions +@@ -78,9 +78,11 @@ struct options { + unsigned int root_unlock_time; + const char *dir; + const char *user; ++ const char *admin_group; + int failures; + uint64_t latest_time; + uid_t uid; ++ int is_admin; + uint64_t now; + }; + +@@ -152,6 +154,9 @@ args_parse(pam_handle_t *pamh, int argc, + opts->root_unlock_time = temp; + } + } ++ else if (strncmp(argv[i], "admin_group=", 12) == 0) { ++ opts->admin_group = argv[i] + 12; ++ } + else if (strcmp(argv[i], "preauth") == 0) { + opts->action = FAILLOCK_ACTION_PREAUTH; + } +@@ -209,6 +214,17 @@ static int get_pam_user(pam_handle_t *pa + } + opts->user = user; + opts->uid = pwd->pw_uid; ++ ++ if (pwd->pw_uid == 0) { ++ opts->is_admin = 1; ++ return PAM_SUCCESS; ++ } ++ ++ if (opts->admin_group && *opts->admin_group) { ++ opts->is_admin = pam_modutil_user_in_group_uid_nam(pamh, ++ pwd->pw_uid, opts->admin_group); ++ } ++ + return PAM_SUCCESS; + } + +@@ -239,7 +255,7 @@ check_tally(pam_handle_t *pamh, struct o + return PAM_SYSTEM_ERR; + } + +- if (opts->uid == 0 && !(opts->flags & FAILLOCK_FLAG_DENY_ROOT)) { ++ if (opts->is_admin && !(opts->flags & FAILLOCK_FLAG_DENY_ROOT)) { + return PAM_SUCCESS; + } + +@@ -262,13 +278,9 @@ check_tally(pam_handle_t *pamh, struct o + + opts->failures = failures; + +- if (opts->uid == 0 && !(opts->flags & FAILLOCK_FLAG_DENY_ROOT)) { +- return PAM_SUCCESS; +- } +- + if (opts->deny && failures >= opts->deny) { +- if ((opts->uid && opts->unlock_time && latest_time + opts->unlock_time < opts->now) || +- (!opts->uid && opts->root_unlock_time && latest_time + opts->root_unlock_time < opts->now)) { ++ if ((!opts->is_admin && opts->unlock_time && latest_time + opts->unlock_time < opts->now) || ++ (opts->is_admin && opts->root_unlock_time && latest_time + opts->root_unlock_time < opts->now)) { + #ifdef HAVE_LIBAUDIT + if (opts->action != FAILLOCK_ACTION_PREAUTH) { /* do not audit in preauth */ + char buf[64]; +@@ -401,7 +413,7 @@ write_tally(pam_handle_t *pamh, struct o + audit_log_user_message(audit_fd, AUDIT_ANOM_LOGIN_FAILURES, buf, + NULL, NULL, NULL, 1); + +- if (opts->uid != 0 || (opts->flags & FAILLOCK_FLAG_DENY_ROOT)) { ++ if (!opts->is_admin || (opts->flags & FAILLOCK_FLAG_DENY_ROOT)) { + audit_log_user_message(audit_fd, AUDIT_RESP_ACCT_LOCK, buf, + NULL, NULL, NULL, 1); + } +@@ -425,11 +437,11 @@ faillock_message(pam_handle_t *pamh, str + int64_t left; + + if (!(opts->flags & FAILLOCK_FLAG_SILENT)) { +- if (opts->uid) { +- left = opts->latest_time + opts->unlock_time - opts->now; ++ if (opts->is_admin) { ++ left = opts->latest_time + opts->root_unlock_time - opts->now; + } + else { +- left = opts->latest_time + opts->root_unlock_time - opts->now; ++ left = opts->latest_time + opts->unlock_time - opts->now; + } + + if (left > 0) { +diff -up Linux-PAM-1.3.0/modules/pam_faillock/pam_faillock.8.xml.admin-group Linux-PAM-1.3.0/modules/pam_faillock/pam_faillock.8.xml +--- Linux-PAM-1.3.0/modules/pam_faillock/pam_faillock.8.xml.admin-group 2016-05-06 15:24:10.328281818 +0200 ++++ Linux-PAM-1.3.0/modules/pam_faillock/pam_faillock.8.xml 2017-08-21 16:16:09.448033843 +0200 +@@ -40,6 +40,9 @@ + root_unlock_time=n + + ++ admin_group=name ++ ++ + audit + + +@@ -243,6 +246,20 @@ + + + ++ ++ ++ ++ ++ ++ ++ If a group name is specified with this option, members ++ of the group will be handled by this module the same as ++ the root account (the options ++ and will apply to them. ++ By default the option is not set. ++ ++ ++ + + + diff --git a/pam-1.2.1-faillock.patch b/pam-1.2.1-faillock.patch new file mode 100644 index 0000000000000000000000000000000000000000..3348ec7119eec2fb258f348e3485474d66e83d6f --- /dev/null +++ b/pam-1.2.1-faillock.patch @@ -0,0 +1,1767 @@ +From: openEuler Buildteam +Date: Sat, 14 Sep 2019 18:35:39 +0800 +Subject: [PATCH] add faillock module + +--- + configure.ac | 2 +- + modules/Makefile.am | 2 +- + modules/pam_faillock/Makefile.am | 44 ++ + modules/pam_faillock/README.xml | 46 ++ + modules/pam_faillock/faillock.8.xml | 123 +++++ + modules/pam_faillock/faillock.c | 158 +++++++ + modules/pam_faillock/faillock.h | 73 +++ + modules/pam_faillock/main.c | 232 ++++++++++ + modules/pam_faillock/pam_faillock.8.xml | 408 +++++++++++++++++ + modules/pam_faillock/pam_faillock.c | 571 ++++++++++++++++++++++++ + modules/pam_faillock/tst-pam_faillock | 2 + + 11 files changed, 1659 insertions(+), 2 deletions(-) + create mode 100644 modules/pam_faillock/Makefile.am + create mode 100644 modules/pam_faillock/README.xml + create mode 100644 modules/pam_faillock/faillock.8.xml + create mode 100644 modules/pam_faillock/faillock.c + create mode 100644 modules/pam_faillock/faillock.h + create mode 100644 modules/pam_faillock/main.c + create mode 100644 modules/pam_faillock/pam_faillock.8.xml + create mode 100644 modules/pam_faillock/pam_faillock.c + create mode 100755 modules/pam_faillock/tst-pam_faillock + +diff --git a/configure.ac b/configure.ac +index 3012ceb..d537907 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -614,7 +614,7 @@ AC_CONFIG_FILES([Makefile libpam/Makefile libpamc/Makefile libpamc/test/Makefile + modules/pam_access/Makefile modules/pam_cracklib/Makefile \ + modules/pam_debug/Makefile modules/pam_deny/Makefile \ + modules/pam_echo/Makefile modules/pam_env/Makefile \ +- modules/pam_faildelay/Makefile \ ++ modules/pam_faildelay/Makefile modules/pam_faillock/Makefile \ + modules/pam_filter/Makefile modules/pam_filter/upperLOWER/Makefile \ + modules/pam_ftp/Makefile modules/pam_group/Makefile \ + modules/pam_issue/Makefile modules/pam_keyinit/Makefile \ +diff --git a/modules/Makefile.am b/modules/Makefile.am +index 4847759..adcc641 100644 +--- a/modules/Makefile.am ++++ b/modules/Makefile.am +@@ -10,7 +10,7 @@ SUBDIRS = pam_access pam_cracklib pam_debug pam_deny pam_echo \ + pam_permit pam_pwhistory pam_rhosts pam_rootok pam_securetty \ + pam_selinux pam_sepermit pam_shells pam_stress \ + pam_succeed_if pam_tally2 pam_time pam_timestamp \ +- pam_tty_audit pam_umask \ ++ pam_tty_audit pam_umask pam_faillock \ + pam_unix pam_userdb pam_warn pam_wheel pam_xauth + + CLEANFILES = *~ +diff --git a/modules/pam_faillock/Makefile.am b/modules/pam_faillock/Makefile.am +new file mode 100644 +index 0000000..dcca280 +--- /dev/null ++++ b/modules/pam_faillock/Makefile.am +@@ -0,0 +1,44 @@ ++# ++# Copyright (c) 2005, 2006, 2007, 2009 Thorsten Kukuk ++# Copyright (c) 2008 Red Hat, Inc. ++# Copyright (c) 2010 Tomas Mraz ++# ++ ++CLEANFILES = *~ ++MAINTAINERCLEANFILES = $(MANS) README ++ ++EXTRA_DIST = README $(MANS) $(XMLS) tst-pam_faillock ++ ++man_MANS = pam_faillock.8 faillock.8 ++XMLS = README.xml pam_faillock.8.xml faillock.8.xml ++ ++TESTS = tst-pam_faillock ++ ++securelibdir = $(SECUREDIR) ++secureconfdir = $(SCONFIGDIR) ++ ++noinst_HEADERS = faillock.h ++ ++faillock_CFLAGS = -I$(top_srcdir)/libpam/include -I$(top_srcdir)/libpamc/include @PIE_CFLAGS@ ++pam_faillock_la_CFLAGS = -I$(top_srcdir)/libpam/include -I$(top_srcdir)/libpamc/include ++ ++pam_faillock_la_LDFLAGS = -no-undefined -avoid-version -module ++pam_faillock_la_LIBADD = -L$(top_builddir)/libpam -lpam $(LIBAUDIT) ++if HAVE_VERSIONING ++ pam_faillock_la_LDFLAGS += -Wl,--version-script=$(srcdir)/../modules.map ++endif ++ ++faillock_LDFLAGS = -Wl,-z,now @PIE_LDFLAGS@ ++faillock_LDADD = -L$(top_builddir)/libpam -lpam $(LIBAUDIT) ++ ++securelib_LTLIBRARIES = pam_faillock.la ++sbin_PROGRAMS = faillock ++ ++pam_faillock_la_SOURCES = pam_faillock.c faillock.c ++faillock_SOURCES = main.c faillock.c ++ ++if ENABLE_REGENERATE_MAN ++noinst_DATA = README ++README: pam_faillock.8.xml ++-include $(top_srcdir)/Make.xml.rules ++endif +diff --git a/modules/pam_faillock/README.xml b/modules/pam_faillock/README.xml +new file mode 100644 +index 0000000..f0654db +--- /dev/null ++++ b/modules/pam_faillock/README.xml +@@ -0,0 +1,46 @@ ++ ++ ++--> ++]> ++ ++
++ ++ ++ ++ ++ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" ++ href="pam_faillock.8.xml" xpointer='xpointer(//refnamediv[@id = "pam_faillock-name"]/*)'/> ++ ++ ++ ++ ++
++ ++
++ ++
++ ++
++ ++
++ ++
++ ++
++ ++
++ ++
++ ++
++ ++
+diff --git a/modules/pam_faillock/faillock.8.xml b/modules/pam_faillock/faillock.8.xml +new file mode 100644 +index 0000000..10942d5 +--- /dev/null ++++ b/modules/pam_faillock/faillock.8.xml +@@ -0,0 +1,123 @@ ++ ++ ++ ++ ++ ++ ++ faillock ++ 8 ++ Linux-PAM Manual ++ ++ ++ ++ faillock ++ Tool for displaying and modifying the authentication failure record files ++ ++ ++ ++ ++ faillock ++ ++ --dir /path/to/tally-directory ++ ++ ++ --user username ++ ++ ++ --reset ++ ++ ++ ++ ++ ++ ++ DESCRIPTION ++ ++ ++ The pam_faillock.so module maintains a list of ++ failed authentication attempts per user during a specified interval ++ and locks the account in case there were more than ++ deny consecutive failed authentications. ++ It stores the failure records into per-user files in the tally ++ directory. ++ ++ ++ The faillock command is an application which ++ can be used to examine and modify the contents of the ++ the tally files. It can display the recent failed authentication ++ attempts of the username or clear the tally ++ files of all or individual usernames. ++ ++ ++ ++ ++ ++ OPTIONS ++ ++ ++ ++ ++ ++ ++ ++ The directory where the user files with the failure records are kept. The ++ default is /var/run/faillock. ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ The user whose failure records should be displayed or cleared. ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Instead of displaying the user's failure records, clear them. ++ ++ ++ ++ ++ ++ ++ ++ FILES ++ ++ ++ /var/run/faillock/* ++ ++ the files logging the authentication failures for users ++ ++ ++ ++ ++ ++ ++ SEE ALSO ++ ++ ++ pam_faillock8 ++ , ++ ++ pam8 ++ ++ ++ ++ ++ ++ AUTHOR ++ ++ faillock was written by Tomas Mraz. ++ ++ ++ ++ +diff --git a/modules/pam_faillock/faillock.c b/modules/pam_faillock/faillock.c +new file mode 100644 +index 0000000..94de18f +--- /dev/null ++++ b/modules/pam_faillock/faillock.c +@@ -0,0 +1,158 @@ ++/* ++ * Copyright (c) 2010 Tomas Mraz ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, and the entire permission notice in its entirety, ++ * including the disclaimer of warranties. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * ALTERNATIVELY, this product may be distributed under the terms of ++ * the GNU Public License, in which case the provisions of the GPL are ++ * required INSTEAD OF the above restrictions. (This clause is ++ * necessary due to a potential bad interaction between the GPL and ++ * the restrictions contained in a BSD-style copyright.) ++ * ++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED ++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, ++ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED ++ * OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include "config.h" ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "faillock.h" ++ ++int ++open_tally (const char *dir, const char *user, uid_t uid, int create) ++{ ++ char *path; ++ int flags = O_RDWR; ++ int fd; ++ ++ if (strstr(user, "../") != NULL) ++ /* just a defensive programming as the user must be a ++ * valid user on the system anyway ++ */ ++ return -1; ++ path = malloc(strlen(dir) + strlen(user) + 2); ++ if (path == NULL) ++ return -1; ++ ++ strcpy(path, dir); ++ if (*dir && dir[strlen(dir) - 1] != '/') { ++ strcat(path, "/"); ++ } ++ strcat(path, user); ++ ++ if (create) { ++ flags |= O_CREAT; ++ } ++ ++ fd = open(path, flags, 0600); ++ ++ free(path); ++ ++ if (fd != -1) { ++ struct stat st; ++ ++ while (flock(fd, LOCK_EX) == -1 && errno == EINTR); ++ if (fstat(fd, &st) == 0) { ++ if (st.st_uid != uid) { ++ fchown(fd, uid, -1); ++ } ++ } ++ } ++ ++ return fd; ++} ++ ++#define CHUNK_SIZE (64 * sizeof(struct tally)) ++#define MAX_RECORDS 1024 ++ ++int ++read_tally(int fd, struct tally_data *tallies) ++{ ++ void *data = NULL, *newdata; ++ unsigned int count = 0; ++ ssize_t chunk = 0; ++ ++ do { ++ newdata = realloc(data, count * sizeof(struct tally) + CHUNK_SIZE); ++ if (newdata == NULL) { ++ free(data); ++ return -1; ++ } ++ ++ data = newdata; ++ ++ chunk = pam_modutil_read(fd, (char *)data + count * sizeof(struct tally), CHUNK_SIZE); ++ if (chunk < 0) { ++ free(data); ++ return -1; ++ } ++ ++ count += chunk/sizeof(struct tally); ++ ++ if (count >= MAX_RECORDS) ++ break; ++ } ++ while (chunk == CHUNK_SIZE); ++ ++ tallies->records = data; ++ tallies->count = count; ++ ++ return 0; ++} ++ ++int ++update_tally(int fd, struct tally_data *tallies) ++{ ++ void *data = tallies->records; ++ unsigned int count = tallies->count; ++ ssize_t chunk; ++ ++ if (tallies->count > MAX_RECORDS) { ++ data = tallies->records + (count - MAX_RECORDS); ++ count = MAX_RECORDS; ++ } ++ ++ if (lseek(fd, 0, SEEK_SET) == (off_t)-1) { ++ return -1; ++ } ++ ++ chunk = pam_modutil_write(fd, data, count * sizeof(struct tally)); ++ ++ if (chunk != (ssize_t)(count * sizeof(struct tally))) { ++ return -1; ++ } ++ ++ if (ftruncate(fd, count * sizeof(struct tally)) == -1) ++ return -1; ++ ++ return 0; ++} +diff --git a/modules/pam_faillock/faillock.h b/modules/pam_faillock/faillock.h +new file mode 100644 +index 0000000..3b732a8 +--- /dev/null ++++ b/modules/pam_faillock/faillock.h +@@ -0,0 +1,73 @@ ++/* ++ * Copyright (c) 2010 Tomas Mraz ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, and the entire permission notice in its entirety, ++ * including the disclaimer of warranties. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * ALTERNATIVELY, this product may be distributed under the terms of ++ * the GNU Public License, in which case the provisions of the GPL are ++ * required INSTEAD OF the above restrictions. (This clause is ++ * necessary due to a potential bad interaction between the GPL and ++ * the restrictions contained in a BSD-style copyright.) ++ * ++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED ++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, ++ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED ++ * OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/* ++ * faillock.h - authentication failure data file record structure ++ * ++ * Each record in the file represents an instance of login failure of ++ * the user at the recorded time ++ */ ++ ++ ++#ifndef _FAILLOCK_H ++#define _FAILLOCK_H ++ ++#include ++#include ++ ++#define TALLY_STATUS_VALID 0x1 /* the tally file entry is valid */ ++#define TALLY_STATUS_RHOST 0x2 /* the source is rhost */ ++#define TALLY_STATUS_TTY 0x4 /* the source is tty - if both TALLY_FLAG_RHOST and TALLY_FLAG_TTY are not set the source is service */ ++ ++struct tally { ++ char source[52]; /* rhost or tty of the login failure (not necessarily NULL terminated) */ ++ uint16_t reserved; /* reserved for future use */ ++ uint16_t status; /* record status */ ++ uint64_t time; /* time of the login failure */ ++}; ++/* 64 bytes per entry */ ++ ++struct tally_data { ++ struct tally *records; /* array of tallies */ ++ unsigned int count; /* number of records */ ++}; ++ ++#define FAILLOCK_DEFAULT_TALLYDIR "/var/run/faillock" ++ ++int open_tally(const char *dir, const char *user, uid_t uid, int create); ++int read_tally(int fd, struct tally_data *tallies); ++int update_tally(int fd, struct tally_data *tallies); ++#endif ++ +diff --git a/modules/pam_faillock/main.c b/modules/pam_faillock/main.c +new file mode 100644 +index 0000000..e83d7d5 +--- /dev/null ++++ b/modules/pam_faillock/main.c +@@ -0,0 +1,232 @@ ++/* ++ * Copyright (c) 2010 Tomas Mraz ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, and the entire permission notice in its entirety, ++ * including the disclaimer of warranties. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * ALTERNATIVELY, this product may be distributed under the terms of ++ * the GNU Public License, in which case the provisions of the GPL are ++ * required INSTEAD OF the above restrictions. (This clause is ++ * necessary due to a potential bad interaction between the GPL and ++ * the restrictions contained in a BSD-style copyright.) ++ * ++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED ++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, ++ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED ++ * OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include "config.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#ifdef HAVE_LIBAUDIT ++#include ++#endif ++ ++#include "faillock.h" ++ ++struct options { ++ unsigned int reset; ++ const char *dir; ++ const char *user; ++ const char *progname; ++}; ++ ++static int ++args_parse(int argc, char **argv, struct options *opts) ++{ ++ int i; ++ memset(opts, 0, sizeof(*opts)); ++ ++ opts->dir = FAILLOCK_DEFAULT_TALLYDIR; ++ opts->progname = argv[0]; ++ ++ for (i = 1; i < argc; ++i) { ++ ++ if (strcmp(argv[i], "--dir") == 0) { ++ ++i; ++ if (i >= argc || strlen(argv[i]) == 0) { ++ fprintf(stderr, "%s: No directory supplied.\n", argv[0]); ++ return -1; ++ } ++ opts->dir = argv[i]; ++ } ++ else if (strcmp(argv[i], "--user") == 0) { ++ ++i; ++ if (i >= argc || strlen(argv[i]) == 0) { ++ fprintf(stderr, "%s: No user name supplied.\n", argv[0]); ++ return -1; ++ } ++ opts->user = argv[i]; ++ } ++ else if (strcmp(argv[i], "--reset") == 0) { ++ opts->reset = 1; ++ } ++ else { ++ fprintf(stderr, "%s: Unknown option: %s\n", argv[0], argv[i]); ++ return -1; ++ } ++ } ++ return 0; ++} ++ ++static void ++usage(const char *progname) ++{ ++ fprintf(stderr, _("Usage: %s [--dir /path/to/tally-directory] [--user username] [--reset]\n"), ++ progname); ++} ++ ++static int ++do_user(struct options *opts, const char *user) ++{ ++ int fd; ++ int rv; ++ struct tally_data tallies; ++ struct passwd *pwd; ++ ++ pwd = getpwnam(user); ++ ++ fd = open_tally(opts->dir, user, pwd != NULL ? pwd->pw_uid : 0, 0); ++ ++ if (fd == -1) { ++ if (errno == ENOENT) { ++ return 0; ++ } ++ else { ++ fprintf(stderr, "%s: Error opening the tally file for %s:", ++ opts->progname, user); ++ perror(NULL); ++ return 3; ++ } ++ } ++ if (opts->reset) { ++#ifdef HAVE_LIBAUDIT ++ int audit_fd; ++#endif ++ ++ while ((rv=ftruncate(fd, 0)) == -1 && errno == EINTR); ++ if (rv == -1) { ++ fprintf(stderr, "%s: Error clearing the tally file for %s:", ++ opts->progname, user); ++ perror(NULL); ++#ifdef HAVE_LIBAUDIT ++ } ++ if ((audit_fd=audit_open()) >= 0) { ++ ++ if (pwd != NULL) { ++ audit_log_acct_message(audit_fd, AUDIT_USER_MGMT, NULL, ++ "faillock-reset", NULL, pwd->pw_uid, NULL, NULL, NULL, rv == 0); ++ } ++ close(audit_fd); ++ } ++ if (rv == -1) { ++#endif ++ close(fd); ++ return 4; ++ } ++ } ++ else { ++ unsigned int i; ++ ++ memset(&tallies, 0, sizeof(tallies)); ++ if ((rv=read_tally(fd, &tallies)) == -1) { ++ fprintf(stderr, "%s: Error reading the tally file for %s:", ++ opts->progname, user); ++ perror(NULL); ++ close(fd); ++ return 5; ++ } ++ ++ printf("%s:\n", user); ++ printf("%-19s %-5s %-48s %-5s\n", "When", "Type", "Source", "Valid"); ++ ++ for (i = 0; i < tallies.count; i++) { ++ struct tm *tm; ++ char timebuf[80]; ++ uint16_t status = tallies.records[i].status; ++ time_t when = tallies.records[i].time; ++ ++ tm = localtime(&when); ++ strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S", tm); ++ printf("%-19s %-5s %-52.52s %s\n", timebuf, ++ status & TALLY_STATUS_RHOST ? "RHOST" : (status & TALLY_STATUS_TTY ? "TTY" : "SVC"), ++ tallies.records[i].source, status & TALLY_STATUS_VALID ? "V":"I"); ++ } ++ free(tallies.records); ++ } ++ close(fd); ++ return 0; ++} ++ ++static int ++do_allusers(struct options *opts) ++{ ++ struct dirent **userlist; ++ int rv, i; ++ ++ rv = scandir(opts->dir, &userlist, NULL, alphasort); ++ if (rv < 0) { ++ fprintf(stderr, "%s: Error reading tally directory: ", opts->progname); ++ perror(NULL); ++ return 2; ++ } ++ ++ for (i = 0; i < rv; i++) { ++ if (userlist[i]->d_name[0] == '.') { ++ if ((userlist[i]->d_name[1] == '.' && userlist[i]->d_name[2] == '\0') || ++ userlist[i]->d_name[1] == '\0') ++ continue; ++ } ++ do_user(opts, userlist[i]->d_name); ++ free(userlist[i]); ++ } ++ free(userlist); ++ ++ return 0; ++} ++ ++ ++/*-----------------------------------------------------------------------*/ ++int ++main (int argc, char *argv[]) ++{ ++ struct options opts; ++ ++ if (args_parse(argc, argv, &opts)) { ++ usage(argv[0]); ++ return 1; ++ } ++ ++ if (opts.user == NULL) { ++ return do_allusers(&opts); ++ } ++ ++ return do_user(&opts, opts.user); ++} ++ +diff --git a/modules/pam_faillock/pam_faillock.8.xml b/modules/pam_faillock/pam_faillock.8.xml +new file mode 100644 +index 0000000..3ba6dd6 +--- /dev/null ++++ b/modules/pam_faillock/pam_faillock.8.xml +@@ -0,0 +1,408 @@ ++ ++ ++ ++ ++ ++ ++ pam_faillock ++ 8 ++ Linux-PAM Manual ++ ++ ++ ++ pam_faillock ++ Module counting authentication failures during a specified interval ++ ++ ++ ++ ++ auth ... pam_faillock.so ++ ++ preauth|authfail|authsucc ++ ++ ++ dir=/path/to/tally-directory ++ ++ ++ even_deny_root ++ ++ ++ deny=n ++ ++ ++ fail_interval=n ++ ++ ++ unlock_time=n ++ ++ ++ root_unlock_time=n ++ ++ ++ audit ++ ++ ++ silent ++ ++ ++ no_log_info ++ ++ ++ ++ account ... pam_faillock.so ++ ++ dir=/path/to/tally-directory ++ ++ ++ no_log_info ++ ++ ++ ++ ++ ++ ++ DESCRIPTION ++ ++ ++ This module maintains a list of failed authentication attempts per ++ user during a specified interval and locks the account in case ++ there were more than deny consecutive ++ failed authentications. ++ ++ ++ Normally, failed attempts to authenticate root will ++ not cause the root account to become ++ blocked, to prevent denial-of-service: if your users aren't given ++ shell accounts and root may only login via su or ++ at the machine console (not telnet/rsh, etc), this is safe. ++ ++ ++ ++ ++ ++ OPTIONS ++ ++ ++ ++ ++ ++ ++ ++ This argument must be set accordingly to the position of this module ++ instance in the PAM stack. ++ ++ ++ The preauth argument must be used when the module ++ is called before the modules which ask for the user credentials such ++ as the password. The module just examines whether the user should ++ be blocked from accessing the service in case there were anomalous ++ number of failed consecutive authentication attempts recently. This ++ call is optional if authsucc is used. ++ ++ ++ The authfail argument must be used when the module ++ is called after the modules which determine the authentication outcome, ++ failed. Unless the user is already blocked due to previous authentication ++ failures, the module will record the failure into the appropriate user ++ tally file. ++ ++ ++ The authsucc argument must be used when the module ++ is called after the modules which determine the authentication outcome, ++ succeded. Unless the user is already blocked due to previous authentication ++ failures, the module will then clear the record of the failures in the ++ respective user tally file. Otherwise it will return authentication error. ++ If this call is not done, the pam_faillock will not distinguish between ++ consecutive and non-consecutive failed authentication attempts. The ++ preauth call must be used in such case. Due to ++ complications in the way the PAM stack can be configured it is also ++ possible to call pam_faillock as an account module. ++ In such configuration the module must be also called in the ++ preauth stage. ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ The directory where the user files with the failure records are kept. The ++ default is /var/run/faillock. ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Will log the user name into the system log if the user is not found. ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Don't print informative messages. This option is implicite ++ in the authfail and authsucc ++ functions. ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Don't log informative messages via syslog3. ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Deny access if the number of consecutive authentication failures ++ for this user during the recent interval exceeds ++ n. The default is 3. ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ The length of the interval during which the consecutive ++ authentication failures must happen for the user account ++ lock out is n seconds. ++ The default is 900 (15 minutes). ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ The access will be reenabled after ++ n seconds after the lock out. ++ The value 0 has the same meaning as value ++ never - the access ++ will not be reenabled without resetting the faillock ++ entries by the faillock8 command. ++ The default is 600 (10 minutes). ++ ++ ++ Note that the default directory that pam_faillock ++ uses is usually cleared on system boot so the access will be also reenabled ++ after system reboot. If that is undesirable a different tally directory ++ must be set with the option. ++ ++ ++ Also note that it is usually undesirable to permanently lock ++ out the users as they can become easily a target of denial of service ++ attack unless the usernames are random and kept secret to potential ++ attackers. ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Root account can become locked as well as regular accounts. ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ This option implies option. ++ Allow access after n seconds ++ to root account after the account is locked. In case the ++ option is not specified the value is the same as of the ++ option. ++ ++ ++ ++ ++ ++ ++ ++ MODULE TYPES PROVIDED ++ ++ The and module types are ++ provided. ++ ++ ++ ++ ++ RETURN VALUES ++ ++ ++ PAM_AUTH_ERR ++ ++ ++ A invalid option was given, the module was not able ++ to retrieve the user name, no valid counter file ++ was found, or too many failed logins. ++ ++ ++ ++ ++ PAM_SUCCESS ++ ++ ++ Everything was successful. ++ ++ ++ ++ ++ PAM_IGNORE ++ ++ ++ User not present in passwd database. ++ ++ ++ ++ ++ ++ ++ ++ NOTES ++ ++ pam_faillock setup in the PAM stack is different ++ from the pam_tally2 module setup. ++ ++ ++ The individual files with the failure records are created as owned by ++ the user. This allows pam_faillock.so module ++ to work correctly when it is called from a screensaver. ++ ++ ++ Note that using the module in without the ++ option or with requisite ++ control field leaks an information about existence or ++ non-existence of an user account in the system because ++ the failures are not recorded for the unknown users. The message ++ about the user account being locked is never displayed for nonexisting ++ user accounts allowing the adversary to infer that a particular account ++ is not existing on a system. ++ ++ ++ ++ ++ EXAMPLES ++ ++ Here are two possible configuration examples for /etc/pam.d/login. ++ They make pam_faillock to lock the account after 4 consecutive ++ failed logins during the default interval of 15 minutes. Root account will be locked ++ as well. The accounts will be automatically unlocked after 20 minutes. ++ ++ ++ In the first example the module is called only in the auth ++ phase and the module does not print any information about the account blocking ++ by pam_faillock. The preauth call can ++ be added to tell the user that his login is blocked by the module and also to abort ++ the authentication without even asking for password in such case. ++ ++ ++auth required pam_securetty.so ++auth required pam_env.so ++auth required pam_nologin.so ++# optionally call: auth requisite pam_faillock.so preauth deny=4 even_deny_root unlock_time=1200 ++# to display the message about account being locked ++auth [success=1 default=bad] pam_unix.so ++auth [default=die] pam_faillock.so authfail deny=4 even_deny_root unlock_time=1200 ++auth sufficient pam_faillock.so authsucc deny=4 even_deny_root unlock_time=1200 ++auth required pam_deny.so ++account required pam_unix.so ++password required pam_unix.so shadow ++session required pam_selinux.so close ++session required pam_loginuid.so ++session required pam_unix.so ++session required pam_selinux.so open ++ ++ ++ In the second example the module is called both in the auth ++ and account phases and the module gives the authenticating ++ user message when the account is locked ++ ++ ++auth required pam_securetty.so ++auth required pam_env.so ++auth required pam_nologin.so ++auth required pam_faillock.so preauth silent deny=4 even_deny_root unlock_time=1200 ++# optionally use requisite above if you do not want to prompt for the password ++# on locked accounts, possibly with removing the silent option as well ++auth sufficient pam_unix.so ++auth [default=die] pam_faillock.so authfail deny=4 even_deny_root unlock_time=1200 ++auth required pam_deny.so ++account required pam_faillock.so ++# if you drop the above call to pam_faillock.so the lock will be done also ++# on non-consecutive authentication failures ++account required pam_unix.so ++password required pam_unix.so shadow ++session required pam_selinux.so close ++session required pam_loginuid.so ++session required pam_unix.so ++session required pam_selinux.so open ++ ++ ++ ++ ++ FILES ++ ++ ++ /var/run/faillock/* ++ ++ the files logging the authentication failures for users ++ ++ ++ ++ ++ ++ ++ SEE ALSO ++ ++ ++ faillock8 ++ , ++ ++ pam.conf5 ++ , ++ ++ pam.d5 ++ , ++ ++ pam8 ++ ++ ++ ++ ++ ++ AUTHOR ++ ++ pam_faillock was written by Tomas Mraz. ++ ++ ++ ++ +diff --git a/modules/pam_faillock/pam_faillock.c b/modules/pam_faillock/pam_faillock.c +new file mode 100644 +index 0000000..5fe9a04 +--- /dev/null ++++ b/modules/pam_faillock/pam_faillock.c +@@ -0,0 +1,571 @@ ++/* ++ * Copyright (c) 2010 Tomas Mraz ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, and the entire permission notice in its entirety, ++ * including the disclaimer of warranties. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * ALTERNATIVELY, this product may be distributed under the terms of ++ * the GNU Public License, in which case the provisions of the GPL are ++ * required INSTEAD OF the above restrictions. (This clause is ++ * necessary due to a potential bad interaction between the GPL and ++ * the restrictions contained in a BSD-style copyright.) ++ * ++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED ++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, ++ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED ++ * OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include "config.h" ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef HAVE_LIBAUDIT ++#include ++#endif ++ ++#include ++#include ++#include ++ ++#include "faillock.h" ++ ++#define PAM_SM_AUTH ++#define PAM_SM_ACCOUNT ++ ++#define FAILLOCK_ACTION_PREAUTH 0 ++#define FAILLOCK_ACTION_AUTHSUCC 1 ++#define FAILLOCK_ACTION_AUTHFAIL 2 ++ ++#define FAILLOCK_FLAG_DENY_ROOT 0x1 ++#define FAILLOCK_FLAG_AUDIT 0x2 ++#define FAILLOCK_FLAG_SILENT 0x4 ++#define FAILLOCK_FLAG_NO_LOG_INFO 0x8 ++#define FAILLOCK_FLAG_UNLOCKED 0x10 ++ ++#define MAX_TIME_INTERVAL 604800 /* 7 days */ ++ ++struct options { ++ unsigned int action; ++ unsigned int flags; ++ unsigned short deny; ++ unsigned int fail_interval; ++ unsigned int unlock_time; ++ unsigned int root_unlock_time; ++ const char *dir; ++ const char *user; ++ int failures; ++ uint64_t latest_time; ++ uid_t uid; ++ uint64_t now; ++}; ++ ++static void ++args_parse(pam_handle_t *pamh, int argc, const char **argv, ++ int flags, struct options *opts) ++{ ++ int i; ++ memset(opts, 0, sizeof(*opts)); ++ ++ opts->dir = FAILLOCK_DEFAULT_TALLYDIR; ++ opts->deny = 3; ++ opts->fail_interval = 900; ++ opts->unlock_time = 600; ++ opts->root_unlock_time = MAX_TIME_INTERVAL+1; ++ ++ for (i = 0; i < argc; ++i) { ++ ++ if (strncmp(argv[i], "dir=", 4) == 0) { ++ if (argv[i][4] != '/') { ++ pam_syslog(pamh, LOG_ERR, ++ "Tally directory is not absolute path (%s); keeping default", argv[i]); ++ } else { ++ opts->dir = argv[i]+4; ++ } ++ } ++ else if (strncmp(argv[i], "deny=", 5) == 0) { ++ if (sscanf(argv[i]+5, "%hu", &opts->deny) != 1) { ++ pam_syslog(pamh, LOG_ERR, ++ "Bad number supplied for deny argument"); ++ } ++ } ++ else if (strncmp(argv[i], "fail_interval=", 14) == 0) { ++ unsigned int temp; ++ if (sscanf(argv[i]+14, "%u", &temp) != 1 || ++ temp > MAX_TIME_INTERVAL) { ++ pam_syslog(pamh, LOG_ERR, ++ "Bad number supplied for fail_interval argument"); ++ } else { ++ opts->fail_interval = temp; ++ } ++ } ++ else if (strncmp(argv[i], "unlock_time=", 12) == 0) { ++ unsigned int temp; ++ ++ if (strcmp(argv[i]+12, "never") == 0) { ++ opts->unlock_time = 0; ++ } ++ else if (sscanf(argv[i]+12, "%u", &temp) != 1 || ++ temp > MAX_TIME_INTERVAL) { ++ pam_syslog(pamh, LOG_ERR, ++ "Bad number supplied for unlock_time argument"); ++ } ++ else { ++ opts->unlock_time = temp; ++ } ++ } ++ else if (strncmp(argv[i], "root_unlock_time=", 17) == 0) { ++ unsigned int temp; ++ ++ if (strcmp(argv[i]+17, "never") == 0) { ++ opts->root_unlock_time = 0; ++ } ++ else if (sscanf(argv[i]+17, "%u", &temp) != 1 || ++ temp > MAX_TIME_INTERVAL) { ++ pam_syslog(pamh, LOG_ERR, ++ "Bad number supplied for root_unlock_time argument"); ++ } else { ++ opts->root_unlock_time = temp; ++ } ++ } ++ else if (strcmp(argv[i], "preauth") == 0) { ++ opts->action = FAILLOCK_ACTION_PREAUTH; ++ } ++ else if (strcmp(argv[i], "authfail") == 0) { ++ opts->action = FAILLOCK_ACTION_AUTHFAIL; ++ } ++ else if (strcmp(argv[i], "authsucc") == 0) { ++ opts->action = FAILLOCK_ACTION_AUTHSUCC; ++ } ++ else if (strcmp(argv[i], "even_deny_root") == 0) { ++ opts->flags |= FAILLOCK_FLAG_DENY_ROOT; ++ } ++ else if (strcmp(argv[i], "audit") == 0) { ++ opts->flags |= FAILLOCK_FLAG_AUDIT; ++ } ++ else if (strcmp(argv[i], "silent") == 0) { ++ opts->flags |= FAILLOCK_FLAG_SILENT; ++ } ++ else if (strcmp(argv[i], "no_log_info") == 0) { ++ opts->flags |= FAILLOCK_FLAG_NO_LOG_INFO; ++ } ++ else { ++ pam_syslog(pamh, LOG_ERR, "Unknown option: %s", argv[i]); ++ } ++ } ++ ++ if (opts->root_unlock_time == MAX_TIME_INTERVAL+1) ++ opts->root_unlock_time = opts->unlock_time; ++ if (flags & PAM_SILENT) ++ opts->flags |= FAILLOCK_FLAG_SILENT; ++} ++ ++static int get_pam_user(pam_handle_t *pamh, struct options *opts) ++{ ++ const char *user; ++ int rv; ++ struct passwd *pwd; ++ ++ if ((rv=pam_get_user(pamh, &user, NULL)) != PAM_SUCCESS) { ++ return rv; ++ } ++ ++ if (*user == '\0') { ++ return PAM_IGNORE; ++ } ++ ++ if ((pwd=pam_modutil_getpwnam(pamh, user)) == NULL) { ++ if (opts->flags & FAILLOCK_FLAG_AUDIT) { ++ pam_syslog(pamh, LOG_ERR, "User unknown: %s", user); ++ } ++ else { ++ pam_syslog(pamh, LOG_ERR, "User unknown"); ++ } ++ return PAM_IGNORE; ++ } ++ opts->user = user; ++ opts->uid = pwd->pw_uid; ++ return PAM_SUCCESS; ++} ++ ++static int ++check_tally(pam_handle_t *pamh, struct options *opts, struct tally_data *tallies, int *fd) ++{ ++ int tfd; ++ unsigned int i; ++ uint64_t latest_time; ++ int failures; ++ ++ opts->now = time(NULL); ++ ++ tfd = open_tally(opts->dir, opts->user, opts->uid, 0); ++ ++ *fd = tfd; ++ ++ if (tfd == -1) { ++ if (errno == EACCES || errno == ENOENT) { ++ return PAM_SUCCESS; ++ } ++ pam_syslog(pamh, LOG_ERR, "Error opening the tally file for %s: %m", opts->user); ++ return PAM_SYSTEM_ERR; ++ } ++ ++ if (read_tally(tfd, tallies) != 0) { ++ pam_syslog(pamh, LOG_ERR, "Error reading the tally file for %s: %m", opts->user); ++ return PAM_SYSTEM_ERR; ++ } ++ ++ if (opts->uid == 0 && !(opts->flags & FAILLOCK_FLAG_DENY_ROOT)) { ++ return PAM_SUCCESS; ++ } ++ ++ latest_time = 0; ++ for(i = 0; i < tallies->count; i++) { ++ if ((tallies->records[i].status & TALLY_STATUS_VALID) && ++ tallies->records[i].time > latest_time) ++ latest_time = tallies->records[i].time; ++ } ++ ++ opts->latest_time = latest_time; ++ ++ failures = 0; ++ for(i = 0; i < tallies->count; i++) { ++ if ((tallies->records[i].status & TALLY_STATUS_VALID) && ++ latest_time - tallies->records[i].time < opts->fail_interval) { ++ ++failures; ++ } ++ } ++ ++ opts->failures = failures; ++ ++ if (opts->uid == 0 && !(opts->flags & FAILLOCK_FLAG_DENY_ROOT)) { ++ return PAM_SUCCESS; ++ } ++ ++ if (opts->deny && failures >= opts->deny) { ++ if ((opts->uid && opts->unlock_time && latest_time + opts->unlock_time < opts->now) || ++ (!opts->uid && opts->root_unlock_time && latest_time + opts->root_unlock_time < opts->now)) { ++#ifdef HAVE_LIBAUDIT ++ if (opts->action != FAILLOCK_ACTION_PREAUTH) { /* do not audit in preauth */ ++ char buf[64]; ++ int audit_fd; ++ const void *rhost = NULL, *tty = NULL; ++ ++ audit_fd = audit_open(); ++ /* If there is an error & audit support is in the kernel report error */ ++ if ((audit_fd < 0) && !(errno == EINVAL || errno == EPROTONOSUPPORT || ++ errno == EAFNOSUPPORT)) ++ return PAM_SYSTEM_ERR; ++ ++ (void)pam_get_item(pamh, PAM_TTY, &tty); ++ (void)pam_get_item(pamh, PAM_RHOST, &rhost); ++ snprintf(buf, sizeof(buf), "pam_faillock uid=%u ", opts->uid); ++ audit_log_user_message(audit_fd, AUDIT_RESP_ACCT_UNLOCK_TIMED, buf, ++ rhost, NULL, tty, 1); ++ } ++#endif ++ opts->flags |= FAILLOCK_FLAG_UNLOCKED; ++ return PAM_SUCCESS; ++ } ++ return PAM_AUTH_ERR; ++ } ++ return PAM_SUCCESS; ++} ++ ++static void ++reset_tally(pam_handle_t *pamh, struct options *opts, int *fd) ++{ ++ int rv; ++ ++ if (*fd == -1) { ++ *fd = open_tally(opts->dir, opts->user, opts->uid, 1); ++ } ++ else { ++ while ((rv=ftruncate(*fd, 0)) == -1 && errno == EINTR); ++ if (rv == -1) { ++ pam_syslog(pamh, LOG_ERR, "Error clearing the tally file for %s: %m", opts->user); ++ } ++ } ++} ++ ++static int ++write_tally(pam_handle_t *pamh, struct options *opts, struct tally_data *tallies, int *fd) ++{ ++ struct tally *records; ++ unsigned int i; ++ int failures; ++ unsigned int oldest; ++ uint64_t oldtime; ++ const void *source = NULL; ++ ++ if (*fd == -1) { ++ *fd = open_tally(opts->dir, opts->user, opts->uid, 1); ++ } ++ if (*fd == -1) { ++ if (errno == EACCES) { ++ return PAM_SUCCESS; ++ } ++ pam_syslog(pamh, LOG_ERR, "Error opening the tally file for %s: %m", opts->user); ++ return PAM_SYSTEM_ERR; ++ } ++ ++ oldtime = 0; ++ oldest = 0; ++ failures = 0; ++ ++ for (i = 0; i < tallies->count; ++i) { ++ if (tallies->records[i].time < oldtime) { ++ oldtime = tallies->records[i].time; ++ oldest = i; ++ } ++ if (opts->flags & FAILLOCK_FLAG_UNLOCKED || ++ opts->now - tallies->records[i].time >= opts->fail_interval ) { ++ tallies->records[i].status &= ~TALLY_STATUS_VALID; ++ } else { ++ ++failures; ++ } ++ } ++ ++ if (oldest >= tallies->count || (tallies->records[oldest].status & TALLY_STATUS_VALID)) { ++ oldest = tallies->count; ++ ++ if ((records=realloc(tallies->records, (oldest+1) * sizeof (*tallies->records))) == NULL) { ++ pam_syslog(pamh, LOG_CRIT, "Error allocating memory for tally records: %m"); ++ return PAM_BUF_ERR; ++ } ++ ++ ++tallies->count; ++ tallies->records = records; ++ } ++ ++ memset(&tallies->records[oldest], 0, sizeof (*tallies->records)); ++ ++ tallies->records[oldest].status = TALLY_STATUS_VALID; ++ if (pam_get_item(pamh, PAM_RHOST, &source) != PAM_SUCCESS || source == NULL) { ++ if (pam_get_item(pamh, PAM_TTY, &source) != PAM_SUCCESS || source == NULL) { ++ if (pam_get_item(pamh, PAM_SERVICE, &source) != PAM_SUCCESS || source == NULL) { ++ source = ""; ++ } ++ } ++ else { ++ tallies->records[oldest].status |= TALLY_STATUS_TTY; ++ } ++ } ++ else { ++ tallies->records[oldest].status |= TALLY_STATUS_RHOST; ++ } ++ ++ strncpy(tallies->records[oldest].source, source, sizeof(tallies->records[oldest].source)); ++ /* source does not have to be null terminated */ ++ ++ tallies->records[oldest].time = opts->now; ++ ++ ++failures; ++ ++ if (opts->deny && failures == opts->deny) { ++#ifdef HAVE_LIBAUDIT ++ char buf[64]; ++ int audit_fd; ++ ++ audit_fd = audit_open(); ++ /* If there is an error & audit support is in the kernel report error */ ++ if ((audit_fd < 0) && !(errno == EINVAL || errno == EPROTONOSUPPORT || ++ errno == EAFNOSUPPORT)) ++ return PAM_SYSTEM_ERR; ++ ++ snprintf(buf, sizeof(buf), "pam_faillock uid=%u ", opts->uid); ++ audit_log_user_message(audit_fd, AUDIT_ANOM_LOGIN_FAILURES, buf, ++ NULL, NULL, NULL, 1); ++ ++ if (opts->uid != 0 || (opts->flags & FAILLOCK_FLAG_DENY_ROOT)) { ++ audit_log_user_message(audit_fd, AUDIT_RESP_ACCT_LOCK, buf, ++ NULL, NULL, NULL, 1); ++ } ++ close(audit_fd); ++#endif ++ if (!(opts->flags & FAILLOCK_FLAG_NO_LOG_INFO)) { ++ pam_syslog(pamh, LOG_INFO, "Consecutive login failures for user %s account temporarily locked", ++ opts->user); ++ } ++ } ++ ++ if (update_tally(*fd, tallies) == 0) ++ return PAM_SUCCESS; ++ ++ return PAM_SYSTEM_ERR; ++} ++ ++static void ++faillock_message(pam_handle_t *pamh, struct options *opts) ++{ ++ int64_t left; ++ ++ if (!(opts->flags & FAILLOCK_FLAG_SILENT)) { ++ if (opts->uid) { ++ left = opts->latest_time + opts->unlock_time - opts->now; ++ } ++ else { ++ left = opts->latest_time + opts->root_unlock_time - opts->now; ++ } ++ ++ if (left > 0) { ++ left = (left + 59)/60; /* minutes */ ++ ++ pam_info(pamh, _("Account temporarily locked due to %d failed logins"), ++ opts->failures); ++ pam_info(pamh, _("(%d minutes left to unlock)"), (int)left); ++ } ++ else { ++ pam_info(pamh, _("Account locked due to %d failed logins"), ++ opts->failures); ++ } ++ } ++} ++ ++static void ++tally_cleanup(struct tally_data *tallies, int fd) ++{ ++ if (fd != -1) { ++ close(fd); ++ } ++ ++ free(tallies->records); ++} ++ ++/*---------------------------------------------------------------------*/ ++ ++PAM_EXTERN int ++pam_sm_authenticate(pam_handle_t *pamh, int flags, ++ int argc, const char **argv) ++{ ++ struct options opts; ++ int rv, fd = -1; ++ struct tally_data tallies; ++ ++ memset(&tallies, 0, sizeof(tallies)); ++ ++ args_parse(pamh, argc, argv, flags, &opts); ++ ++ pam_fail_delay(pamh, 2000000); /* 2 sec delay for on failure */ ++ ++ if ((rv=get_pam_user(pamh, &opts)) != PAM_SUCCESS) { ++ return rv; ++ } ++ ++ switch (opts.action) { ++ case FAILLOCK_ACTION_PREAUTH: ++ rv = check_tally(pamh, &opts, &tallies, &fd); ++ if (rv == PAM_AUTH_ERR && !(opts.flags & FAILLOCK_FLAG_SILENT)) { ++ faillock_message(pamh, &opts); ++ } ++ break; ++ ++ case FAILLOCK_ACTION_AUTHSUCC: ++ rv = check_tally(pamh, &opts, &tallies, &fd); ++ if (rv == PAM_SUCCESS) { ++ reset_tally(pamh, &opts, &fd); ++ } ++ break; ++ ++ case FAILLOCK_ACTION_AUTHFAIL: ++ rv = check_tally(pamh, &opts, &tallies, &fd); ++ if (rv == PAM_SUCCESS) { ++ rv = PAM_IGNORE; /* this return value should be ignored */ ++ write_tally(pamh, &opts, &tallies, &fd); ++ } ++ break; ++ } ++ ++ tally_cleanup(&tallies, fd); ++ ++ return rv; ++} ++ ++/*---------------------------------------------------------------------*/ ++ ++PAM_EXTERN int ++pam_sm_setcred(pam_handle_t *pamh UNUSED, int flags UNUSED, ++ int argc UNUSED, const char **argv UNUSED) ++{ ++ return PAM_SUCCESS; ++} ++ ++/*---------------------------------------------------------------------*/ ++ ++PAM_EXTERN int ++pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, ++ int argc, const char **argv) ++{ ++ struct options opts; ++ int rv, fd = -1; ++ struct tally_data tallies; ++ ++ memset(&tallies, 0, sizeof(tallies)); ++ ++ args_parse(pamh, argc, argv, flags, &opts); ++ ++ opts.action = FAILLOCK_ACTION_AUTHSUCC; ++ ++ if ((rv=get_pam_user(pamh, &opts)) != PAM_SUCCESS) { ++ return rv; ++ } ++ ++ check_tally(pamh, &opts, &tallies, &fd); /* for auditing */ ++ reset_tally(pamh, &opts, &fd); ++ ++ tally_cleanup(&tallies, fd); ++ ++ return PAM_SUCCESS; ++} ++ ++/*-----------------------------------------------------------------------*/ ++ ++#ifdef PAM_STATIC ++ ++/* static module data */ ++ ++struct pam_module _pam_faillock_modstruct = { ++ MODULE_NAME, ++#ifdef PAM_SM_AUTH ++ pam_sm_authenticate, ++ pam_sm_setcred, ++#else ++ NULL, ++ NULL, ++#endif ++#ifdef PAM_SM_ACCOUNT ++ pam_sm_acct_mgmt, ++#else ++ NULL, ++#endif ++ NULL, ++ NULL, ++ NULL, ++}; ++ ++#endif /* #ifdef PAM_STATIC */ ++ +diff --git a/modules/pam_faillock/tst-pam_faillock b/modules/pam_faillock/tst-pam_faillock +new file mode 100755 +index 0000000..ec454c2 +--- /dev/null ++++ b/modules/pam_faillock/tst-pam_faillock +@@ -0,0 +1,2 @@ ++#!/bin/sh ++../../tests/tst-dlopen .libs/pam_faillock.so +-- +2.19.1 + diff --git a/pam-1.3.0-pwhistory-helper.patch b/pam-1.3.0-pwhistory-helper.patch new file mode 100644 index 0000000000000000000000000000000000000000..554e5c8f83cd1888eb21d6a36b62bf7778b625e3 --- /dev/null +++ b/pam-1.3.0-pwhistory-helper.patch @@ -0,0 +1,806 @@ +diff -up Linux-PAM-1.3.0/modules/pam_pwhistory/Makefile.am.pwhhelper Linux-PAM-1.3.0/modules/pam_pwhistory/Makefile.am +--- Linux-PAM-1.3.0/modules/pam_pwhistory/Makefile.am.pwhhelper 2016-03-24 12:45:42.000000000 +0100 ++++ Linux-PAM-1.3.0/modules/pam_pwhistory/Makefile.am 2016-05-06 15:18:42.307637933 +0200 +@@ -1,5 +1,6 @@ + # + # Copyright (c) 2008, 2009 Thorsten Kukuk ++# Copyright (c) 2013 Red Hat, Inc. + # + + CLEANFILES = *~ +@@ -9,25 +10,34 @@ EXTRA_DIST = README $(MANS) $(XMLS) tst- + + TESTS = tst-pam_pwhistory + +-man_MANS = pam_pwhistory.8 ++man_MANS = pam_pwhistory.8 pwhistory_helper.8 + +-XMLS = README.xml pam_pwhistory.8.xml ++XMLS = README.xml pam_pwhistory.8.xml pwhistory_helper.8.xml + + securelibdir = $(SECUREDIR) + secureconfdir = $(SCONFIGDIR) + +-AM_CFLAGS = -I$(top_srcdir)/libpam/include -I$(top_srcdir)/libpamc/include +-AM_LDFLAGS = -no-undefined -avoid-version -module ++AM_CFLAGS = -I$(top_srcdir)/libpam/include -I$(top_srcdir)/libpamc/include \ ++ -DPWHISTORY_HELPER=\"$(sbindir)/pwhistory_helper\" ++ ++pam_pwhistory_la_LDFLAGS = -no-undefined -avoid-version -module + if HAVE_VERSIONING +- AM_LDFLAGS += -Wl,--version-script=$(srcdir)/../modules.map ++ pam_pwhistory_la_LDFLAGS += -Wl,--version-script=$(srcdir)/../modules.map + endif + + noinst_HEADERS = opasswd.h + + securelib_LTLIBRARIES = pam_pwhistory.la +-pam_pwhistory_la_LIBADD = $(top_builddir)/libpam/libpam.la @LIBCRYPT@ ++pam_pwhistory_la_CFLAGS = $(AM_CFLAGS) ++pam_pwhistory_la_LIBADD = $(top_builddir)/libpam/libpam.la @LIBCRYPT@ @LIBSELINUX@ + pam_pwhistory_la_SOURCES = pam_pwhistory.c opasswd.c + ++sbin_PROGRAMS = pwhistory_helper ++pwhistory_helper_CFLAGS = $(AM_CFLAGS) -DHELPER_COMPILE=\"pwhistory_helper\" @PIE_CFLAGS@ ++pwhistory_helper_SOURCES = pwhistory_helper.c opasswd.c ++pwhistory_helper_LDFLAGS = -Wl,-z,now @PIE_LDFLAGS@ ++pwhistory_helper_LDADD = $(top_builddir)/libpam/libpam.la @LIBCRYPT@ ++ + if ENABLE_REGENERATE_MAN + noinst_DATA = README + README: pam_pwhistory.8.xml +diff -up Linux-PAM-1.3.0/modules/pam_pwhistory/opasswd.c.pwhhelper Linux-PAM-1.3.0/modules/pam_pwhistory/opasswd.c +--- Linux-PAM-1.3.0/modules/pam_pwhistory/opasswd.c.pwhhelper 2016-03-24 12:45:42.000000000 +0100 ++++ Linux-PAM-1.3.0/modules/pam_pwhistory/opasswd.c 2016-05-06 15:18:42.307637933 +0200 +@@ -1,5 +1,6 @@ + /* + * Copyright (c) 2008 Thorsten Kukuk ++ * Copyright (c) 2013 Red Hat, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions +@@ -38,6 +39,7 @@ + #endif + + #include ++#include + #include + #include + #include +@@ -47,6 +49,7 @@ + #include + #include + #include ++#include + #include + + #if defined (HAVE_XCRYPT_H) +@@ -55,7 +58,14 @@ + #include + #endif + ++#ifdef HELPER_COMPILE ++#define pam_modutil_getpwnam(h,n) getpwnam(n) ++#define pam_modutil_getspnam(h,n) getspnam(n) ++#define pam_syslog(h,a,...) helper_log_err(a,__VA_ARGS__) ++#else ++#include + #include ++#endif + #include + + #include "opasswd.h" +@@ -76,6 +86,19 @@ typedef struct { + char *old_passwords; + } opwd; + ++#ifdef HELPER_COMPILE ++void ++helper_log_err(int err, const char *format, ...) ++{ ++ va_list args; ++ ++ va_start(args, format); ++ openlog(HELPER_COMPILE, LOG_CONS | LOG_PID, LOG_AUTHPRIV); ++ vsyslog(err, format, args); ++ va_end(args); ++ closelog(); ++} ++#endif + + static int + parse_entry (char *line, opwd *data) +@@ -117,8 +140,8 @@ compare_password(const char *newpass, co + } + + /* Check, if the new password is already in the opasswd file. */ +-int +-check_old_pass (pam_handle_t *pamh, const char *user, ++PAMH_ARG_DECL(int ++check_old_pass, const char *user, + const char *newpass, int debug) + { + int retval = PAM_SUCCESS; +@@ -128,6 +151,11 @@ check_old_pass (pam_handle_t *pamh, cons + opwd entry; + int found = 0; + ++#ifndef HELPER_COMPILE ++ if (SELINUX_ENABLED) ++ return PAM_PWHISTORY_RUN_HELPER; ++#endif ++ + if ((oldpf = fopen (OLD_PASSWORDS_FILE, "r")) == NULL) + { + if (errno != ENOENT) +@@ -213,9 +241,9 @@ check_old_pass (pam_handle_t *pamh, cons + return retval; + } + +-int +-save_old_pass (pam_handle_t *pamh, const char *user, uid_t uid, +- const char *oldpass, int howmany, int debug UNUSED) ++PAMH_ARG_DECL(int ++save_old_pass, const char *user, ++ int howmany, int debug UNUSED) + { + char opasswd_tmp[] = TMP_PASSWORDS_FILE; + struct stat opasswd_stat; +@@ -226,10 +254,35 @@ save_old_pass (pam_handle_t *pamh, const + char *buf = NULL; + size_t buflen = 0; + int found = 0; ++ struct passwd *pwd; ++ const char *oldpass; ++ ++ pwd = pam_modutil_getpwnam (pamh, user); ++ if (pwd == NULL) ++ return PAM_USER_UNKNOWN; + + if (howmany <= 0) + return PAM_SUCCESS; + ++#ifndef HELPER_COMPILE ++ if (SELINUX_ENABLED) ++ return PAM_PWHISTORY_RUN_HELPER; ++#endif ++ ++ if ((strcmp(pwd->pw_passwd, "x") == 0) || ++ ((pwd->pw_passwd[0] == '#') && ++ (pwd->pw_passwd[1] == '#') && ++ (strcmp(pwd->pw_name, pwd->pw_passwd + 2) == 0))) ++ { ++ struct spwd *spw = pam_modutil_getspnam (pamh, user); ++ ++ if (spw == NULL) ++ return PAM_USER_UNKNOWN; ++ oldpass = spw->sp_pwdp; ++ } ++ else ++ oldpass = pwd->pw_passwd; ++ + if (oldpass == NULL || *oldpass == '\0') + return PAM_SUCCESS; + +@@ -452,7 +505,7 @@ save_old_pass (pam_handle_t *pamh, const + { + char *out; + +- if (asprintf (&out, "%s:%d:1:%s\n", user, uid, oldpass) < 0) ++ if (asprintf (&out, "%s:%d:1:%s\n", user, pwd->pw_uid, oldpass) < 0) + { + retval = PAM_AUTHTOK_ERR; + if (oldpf) +diff -up Linux-PAM-1.3.0/modules/pam_pwhistory/opasswd.h.pwhhelper Linux-PAM-1.3.0/modules/pam_pwhistory/opasswd.h +--- Linux-PAM-1.3.0/modules/pam_pwhistory/opasswd.h.pwhhelper 2016-03-24 12:45:42.000000000 +0100 ++++ Linux-PAM-1.3.0/modules/pam_pwhistory/opasswd.h 2016-05-06 15:18:42.307637933 +0200 +@@ -1,5 +1,6 @@ + /* + * Copyright (c) 2008 Thorsten Kukuk ++ * Copyright (c) 2013 Red Hat, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions +@@ -36,10 +37,32 @@ + #ifndef __OPASSWD_H__ + #define __OPASSWD_H__ + +-extern int check_old_pass (pam_handle_t *pamh, const char *user, +- const char *newpass, int debug); +-extern int save_old_pass (pam_handle_t *pamh, const char *user, +- uid_t uid, const char *oldpass, +- int howmany, int debug); ++#define PAM_PWHISTORY_RUN_HELPER PAM_CRED_INSUFFICIENT ++ ++#ifdef WITH_SELINUX ++#include ++#define SELINUX_ENABLED is_selinux_enabled()>0 ++#else ++#define SELINUX_ENABLED 0 ++#endif ++ ++#ifdef HELPER_COMPILE ++#define PAMH_ARG_DECL(fname, ...) fname(__VA_ARGS__) ++#define PAMH_ARG(...) __VA_ARGS__ ++#else ++#define PAMH_ARG_DECL(fname, ...) fname(pam_handle_t *pamh, __VA_ARGS__) ++#define PAMH_ARG(...) pamh, __VA_ARGS__ ++#endif ++ ++#ifdef HELPER_COMPILE ++void ++helper_log_err(int err, const char *format, ...); ++#endif ++ ++PAMH_ARG_DECL(int ++check_old_pass, const char *user, const char *newpass, int debug); ++ ++PAMH_ARG_DECL(int ++save_old_pass, const char *user, int howmany, int debug); + + #endif /* __OPASSWD_H__ */ +diff -up Linux-PAM-1.3.0/modules/pam_pwhistory/pam_pwhistory.c.pwhhelper Linux-PAM-1.3.0/modules/pam_pwhistory/pam_pwhistory.c +--- Linux-PAM-1.3.0/modules/pam_pwhistory/pam_pwhistory.c.pwhhelper 2016-04-04 11:22:28.000000000 +0200 ++++ Linux-PAM-1.3.0/modules/pam_pwhistory/pam_pwhistory.c 2016-05-06 15:19:31.610785512 +0200 +@@ -1,6 +1,7 @@ + /* + * Copyright (c) 2008, 2012 Thorsten Kukuk + * Author: Thorsten Kukuk ++ * Copyright (c) 2013 Red Hat, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions +@@ -46,10 +47,14 @@ + #include + #include + #include +-#include + #include + #include + #include ++#include ++#include ++#include ++#include ++#include + + #include + #include +@@ -59,6 +64,7 @@ + #include "opasswd.h" + + #define DEFAULT_BUFLEN 2048 ++#define MAX_FD_NO 20000 + + struct options_t { + int debug; +@@ -102,6 +108,184 @@ parse_option (pam_handle_t *pamh, const + pam_syslog (pamh, LOG_ERR, "pam_pwhistory: unknown option: %s", argv); + } + ++static int ++run_save_helper(pam_handle_t *pamh, const char *user, ++ int howmany, int debug) ++{ ++ int retval, child; ++ struct sigaction newsa, oldsa; ++ ++ memset(&newsa, '\0', sizeof(newsa)); ++ newsa.sa_handler = SIG_DFL; ++ sigaction(SIGCHLD, &newsa, &oldsa); ++ ++ child = fork(); ++ if (child == 0) ++ { ++ int i = 0; ++ struct rlimit rlim; ++ int dummyfds[2]; ++ static char *envp[] = { NULL }; ++ char *args[] = { NULL, NULL, NULL, NULL, NULL, NULL }; ++ ++ /* replace std file descriptors with a dummy pipe */ ++ if (pipe2(dummyfds, O_NONBLOCK) == 0) ++ { ++ dup2(dummyfds[0], STDIN_FILENO); ++ dup2(dummyfds[1], STDOUT_FILENO); ++ dup2(dummyfds[1], STDERR_FILENO); ++ } ++ ++ if (getrlimit(RLIMIT_NOFILE,&rlim) == 0) ++ { ++ if (rlim.rlim_max >= MAX_FD_NO) ++ rlim.rlim_max = MAX_FD_NO; ++ for (i = STDERR_FILENO + 1; i < (int)rlim.rlim_max; i++) ++ { ++ if (i != dummyfds[0]) ++ close(i); ++ } ++ } ++ ++ /* exec binary helper */ ++ args[0] = strdup(PWHISTORY_HELPER); ++ args[1] = strdup("save"); ++ args[2] = x_strdup(user); ++ asprintf(&args[3], "%d", howmany); ++ asprintf(&args[4], "%d", debug); ++ ++ execve(args[0], args, envp); ++ ++ _exit(PAM_SYSTEM_ERR); ++ } ++ else if (child > 0) ++ { ++ /* wait for child */ ++ int rc = 0; ++ rc = waitpid(child, &retval, 0); /* wait for helper to complete */ ++ if (rc < 0) ++ { ++ pam_syslog(pamh, LOG_ERR, "pwhistory_helper save waitpid returned %d: %m", rc); ++ retval = PAM_SYSTEM_ERR; ++ } ++ else if (!WIFEXITED(retval)) ++ { ++ pam_syslog(pamh, LOG_ERR, "pwhistory_helper save abnormal exit: %d", retval); ++ retval = PAM_SYSTEM_ERR; ++ } ++ else ++ { ++ retval = WEXITSTATUS(retval); ++ } ++ } ++ else ++ { ++ retval = PAM_SYSTEM_ERR; ++ } ++ ++ sigaction(SIGCHLD, &oldsa, NULL); /* restore old signal handler */ ++ ++ return retval; ++} ++ ++static int ++run_check_helper(pam_handle_t *pamh, const char *user, ++ const char *newpass, int debug) ++{ ++ int retval, child, fds[2]; ++ struct sigaction newsa, oldsa; ++ ++ /* create a pipe for the password */ ++ if (pipe(fds) != 0) ++ return PAM_SYSTEM_ERR; ++ ++ memset(&newsa, '\0', sizeof(newsa)); ++ newsa.sa_handler = SIG_DFL; ++ sigaction(SIGCHLD, &newsa, &oldsa); ++ ++ child = fork(); ++ if (child == 0) ++ { ++ int i = 0; ++ struct rlimit rlim; ++ int dummyfds[2]; ++ static char *envp[] = { NULL }; ++ char *args[] = { NULL, NULL, NULL, NULL, NULL }; ++ ++ /* reopen stdin as pipe */ ++ dup2(fds[0], STDIN_FILENO); ++ ++ /* replace std file descriptors with a dummy pipe */ ++ if (pipe2(dummyfds, O_NONBLOCK) == 0) ++ { ++ dup2(dummyfds[1], STDOUT_FILENO); ++ dup2(dummyfds[1], STDERR_FILENO); ++ } ++ ++ if (getrlimit(RLIMIT_NOFILE,&rlim) == 0) ++ { ++ if (rlim.rlim_max >= MAX_FD_NO) ++ rlim.rlim_max = MAX_FD_NO; ++ for (i = STDERR_FILENO + 1; i < (int)rlim.rlim_max; i++) ++ { ++ if (i != dummyfds[0]) ++ close(i); ++ } ++ } ++ ++ /* exec binary helper */ ++ args[0] = strdup(PWHISTORY_HELPER); ++ args[1] = strdup("check"); ++ args[2] = x_strdup(user); ++ asprintf(&args[3], "%d", debug); ++ ++ execve(args[0], args, envp); ++ ++ _exit(PAM_SYSTEM_ERR); ++ } ++ else if (child > 0) ++ { ++ /* wait for child */ ++ int rc = 0; ++ if (newpass == NULL) ++ newpass = ""; ++ ++ /* send the password to the child */ ++ if (write(fds[1], newpass, strlen(newpass)+1) == -1) ++ { ++ pam_syslog(pamh, LOG_ERR, "Cannot send password to helper: %m"); ++ retval = PAM_SYSTEM_ERR; ++ } ++ newpass = NULL; ++ close(fds[0]); /* close here to avoid possible SIGPIPE above */ ++ close(fds[1]); ++ rc = waitpid(child, &retval, 0); /* wait for helper to complete */ ++ if (rc < 0) ++ { ++ pam_syslog(pamh, LOG_ERR, "pwhistory_helper check waitpid returned %d: %m", rc); ++ retval = PAM_SYSTEM_ERR; ++ } ++ else if (!WIFEXITED(retval)) ++ { ++ pam_syslog(pamh, LOG_ERR, "pwhistory_helper check abnormal exit: %d", retval); ++ retval = PAM_SYSTEM_ERR; ++ } ++ else ++ { ++ retval = WEXITSTATUS(retval); ++ } ++ } ++ else ++ { ++ close(fds[0]); ++ close(fds[1]); ++ retval = PAM_SYSTEM_ERR; ++ } ++ ++ sigaction(SIGCHLD, &oldsa, NULL); /* restore old signal handler */ ++ ++ return retval; ++} + + /* This module saves the current crypted password in /etc/security/opasswd + and then compares the new password with all entries in this file. */ +@@ -109,7 +293,6 @@ parse_option (pam_handle_t *pamh, const + int + pam_sm_chauthtok (pam_handle_t *pamh, int flags, int argc, const char **argv) + { +- struct passwd *pwd; + const char *newpass; + const char *user; + int retval, tries; +@@ -154,31 +337,13 @@ pam_sm_chauthtok (pam_handle_t *pamh, in + return PAM_SUCCESS; + } + +- pwd = pam_modutil_getpwnam (pamh, user); +- if (pwd == NULL) +- return PAM_USER_UNKNOWN; +- +- if ((strcmp(pwd->pw_passwd, "x") == 0) || +- ((pwd->pw_passwd[0] == '#') && +- (pwd->pw_passwd[1] == '#') && +- (strcmp(pwd->pw_name, pwd->pw_passwd + 2) == 0))) +- { +- struct spwd *spw = pam_modutil_getspnam (pamh, user); +- if (spw == NULL) +- return PAM_USER_UNKNOWN; ++ retval = save_old_pass (pamh, user, options.remember, options.debug); + +- retval = save_old_pass (pamh, user, pwd->pw_uid, spw->sp_pwdp, +- options.remember, options.debug); +- if (retval != PAM_SUCCESS) +- return retval; +- } +- else +- { +- retval = save_old_pass (pamh, user, pwd->pw_uid, pwd->pw_passwd, +- options.remember, options.debug); +- if (retval != PAM_SUCCESS) +- return retval; +- } ++ if (retval == PAM_PWHISTORY_RUN_HELPER) ++ retval = run_save_helper(pamh, user, options.remember, options.debug); ++ ++ if (retval != PAM_SUCCESS) ++ return retval; + + newpass = NULL; + tries = 0; +@@ -207,8 +372,11 @@ pam_sm_chauthtok (pam_handle_t *pamh, in + if (options.debug) + pam_syslog (pamh, LOG_DEBUG, "check against old password file"); + +- if (check_old_pass (pamh, user, newpass, +- options.debug) != PAM_SUCCESS) ++ retval = check_old_pass (pamh, user, newpass, options.debug); ++ if (retval == PAM_PWHISTORY_RUN_HELPER) ++ retval = run_check_helper(pamh, user, newpass, options.debug); ++ ++ if (retval != PAM_SUCCESS) + { + if (getuid() || options.enforce_for_root || + (flags & PAM_CHANGE_EXPIRED_AUTHTOK)) +diff -up Linux-PAM-1.3.0/modules/pam_pwhistory/pwhistory_helper.c.pwhhelper Linux-PAM-1.3.0/modules/pam_pwhistory/pwhistory_helper.c +--- Linux-PAM-1.3.0/modules/pam_pwhistory/pwhistory_helper.c.pwhhelper 2016-05-06 15:18:42.308637957 +0200 ++++ Linux-PAM-1.3.0/modules/pam_pwhistory/pwhistory_helper.c 2016-05-06 15:18:42.308637957 +0200 +@@ -0,0 +1,209 @@ ++/* ++ * Copyright (c) 2013 Red Hat, Inc. ++ * Author: Tomas Mraz ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, and the entire permission notice in its entirety, ++ * including the disclaimer of warranties. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * ALTERNATIVELY, this product may be distributed under the terms of ++ * the GNU Public License, in which case the provisions of the GPL are ++ * required INSTEAD OF the above restrictions. (This clause is ++ * necessary due to a potential bad interaction between the GPL and ++ * the restrictions contained in a BSD-style copyright.) ++ * ++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED ++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, ++ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED ++ * OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include "config.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "opasswd.h" ++ ++#define MAXPASS 200 ++ ++static void ++su_sighandler(int sig) ++{ ++#ifndef SA_RESETHAND ++ /* emulate the behaviour of the SA_RESETHAND flag */ ++ if ( sig == SIGILL || sig == SIGTRAP || sig == SIGBUS || sig = SIGSERV ) { ++ struct sigaction sa; ++ memset(&sa, '\0', sizeof(sa)); ++ sa.sa_handler = SIG_DFL; ++ sigaction(sig, &sa, NULL); ++ } ++#endif ++ if (sig > 0) { ++ _exit(sig); ++ } ++} ++ ++static void ++setup_signals(void) ++{ ++ struct sigaction action; /* posix signal structure */ ++ ++ /* ++ * Setup signal handlers ++ */ ++ (void) memset((void *) &action, 0, sizeof(action)); ++ action.sa_handler = su_sighandler; ++#ifdef SA_RESETHAND ++ action.sa_flags = SA_RESETHAND; ++#endif ++ (void) sigaction(SIGILL, &action, NULL); ++ (void) sigaction(SIGTRAP, &action, NULL); ++ (void) sigaction(SIGBUS, &action, NULL); ++ (void) sigaction(SIGSEGV, &action, NULL); ++ action.sa_handler = SIG_IGN; ++ action.sa_flags = 0; ++ (void) sigaction(SIGTERM, &action, NULL); ++ (void) sigaction(SIGHUP, &action, NULL); ++ (void) sigaction(SIGINT, &action, NULL); ++ (void) sigaction(SIGQUIT, &action, NULL); ++} ++ ++static int ++read_passwords(int fd, int npass, char **passwords) ++{ ++ int rbytes = 0; ++ int offset = 0; ++ int i = 0; ++ char *pptr; ++ while (npass > 0) ++ { ++ rbytes = read(fd, passwords[i]+offset, MAXPASS-offset); ++ ++ if (rbytes < 0) ++ { ++ if (errno == EINTR) continue; ++ break; ++ } ++ if (rbytes == 0) ++ break; ++ ++ while (npass > 0 && (pptr=memchr(passwords[i]+offset, '\0', rbytes)) ++ != NULL) ++ { ++ rbytes -= pptr - (passwords[i]+offset) + 1; ++ i++; ++ offset = 0; ++ npass--; ++ if (rbytes > 0) ++ { ++ if (npass > 0) ++ memcpy(passwords[i], pptr+1, rbytes); ++ memset(pptr+1, '\0', rbytes); ++ } ++ } ++ offset += rbytes; ++ } ++ ++ /* clear up */ ++ if (offset > 0 && npass > 0) ++ memset(passwords[i], '\0', offset); ++ ++ return i; ++} ++ ++ ++static int ++check_history(const char *user, const char *debug) ++{ ++ char pass[MAXPASS + 1]; ++ char *passwords[] = { pass }; ++ int npass; ++ int dbg = atoi(debug); /* no need to be too fancy here */ ++ int retval; ++ ++ /* read the password from stdin (a pipe from the pam_pwhistory module) */ ++ npass = read_passwords(STDIN_FILENO, 1, passwords); ++ ++ if (npass != 1) ++ { /* is it a valid password? */ ++ helper_log_err(LOG_DEBUG, "no password supplied"); ++ return PAM_AUTHTOK_ERR; ++ } ++ ++ retval = check_old_pass(user, pass, dbg); ++ ++ memset(pass, '\0', MAXPASS); /* clear memory of the password */ ++ ++ return retval; ++} ++ ++static int ++save_history(const char *user, const char *howmany, const char *debug) ++{ ++ int num = atoi(howmany); ++ int dbg = atoi(debug); /* no need to be too fancy here */ ++ int retval; ++ ++ retval = save_old_pass(user, num, dbg); ++ ++ return retval; ++} ++ ++int ++main(int argc, char *argv[]) ++{ ++ const char *option; ++ const char *user; ++ ++ /* ++ * Catch or ignore as many signal as possible. ++ */ ++ setup_signals(); ++ ++ /* ++ * we establish that this program is running with non-tty stdin. ++ * this is to discourage casual use. ++ */ ++ ++ if (isatty(STDIN_FILENO) || argc < 4) ++ { ++ fprintf(stderr, ++ "This binary is not designed for running in this way.\n"); ++ sleep(10); /* this should discourage/annoy the user */ ++ return PAM_SYSTEM_ERR; ++ } ++ ++ option = argv[1]; ++ user = argv[2]; ++ ++ if (strcmp(option, "check") == 0 && argc == 4) ++ return check_history(user, argv[3]); ++ else if (strcmp(option, "save") == 0 && argc == 5) ++ return save_history(user, argv[3], argv[4]); ++ ++ return PAM_SYSTEM_ERR; ++} ++ +diff -up Linux-PAM-1.3.0/modules/pam_pwhistory/pwhistory_helper.8.xml.pwhhelper Linux-PAM-1.3.0/modules/pam_pwhistory/pwhistory_helper.8.xml +--- Linux-PAM-1.3.0/modules/pam_pwhistory/pwhistory_helper.8.xml.pwhhelper 2016-05-06 15:18:42.308637957 +0200 ++++ Linux-PAM-1.3.0/modules/pam_pwhistory/pwhistory_helper.8.xml 2016-05-06 15:18:42.308637957 +0200 +@@ -0,0 +1,68 @@ ++ ++ ++ ++ ++ ++ ++ pwhistory_helper ++ 8 ++ Linux-PAM Manual ++ ++ ++ ++ pwhistory_helper ++ Helper binary that transfers password hashes from passwd or shadow to opasswd ++ ++ ++ ++ ++ pwhistory_helper ++ ++ ... ++ ++ ++ ++ ++ ++ ++ DESCRIPTION ++ ++ ++ pwhistory_helper is a helper program for the ++ pam_pwhistory module that transfers password hashes ++ from passwd or shadow file to the opasswd file and checks a password ++ supplied by user against the existing hashes in the opasswd file. ++ ++ ++ ++ The purpose of the helper is to enable tighter confinement of ++ login and password changing services. The helper is thus called only ++ when SELinux is enabled on the system. ++ ++ ++ ++ The interface of the helper - command line options, and input/output ++ data format are internal to the pam_pwhistory ++ module and it should not be called directly from applications. ++ ++ ++ ++ ++ SEE ALSO ++ ++ ++ pam_pwhistory8 ++ ++ ++ ++ ++ ++ AUTHOR ++ ++ Written by Tomas Mraz based on the code originally in ++ pam_pwhistory and pam_unix modules. ++ ++ ++ ++ diff --git a/pam-1.3.0-unix-nomsg.patch b/pam-1.3.0-unix-nomsg.patch new file mode 100644 index 0000000000000000000000000000000000000000..33c226773ca246226a6f2145f18f2d160f30201d --- /dev/null +++ b/pam-1.3.0-unix-nomsg.patch @@ -0,0 +1,16 @@ +diff -up Linux-PAM-1.3.0/modules/pam_unix/pam_unix_passwd.c.nomsg Linux-PAM-1.3.0/modules/pam_unix/pam_unix_passwd.c +--- Linux-PAM-1.3.0/modules/pam_unix/pam_unix_passwd.c.nomsg 2016-04-11 13:08:47.000000000 +0200 ++++ Linux-PAM-1.3.0/modules/pam_unix/pam_unix_passwd.c 2017-04-20 16:51:24.853106709 +0200 +@@ -687,12 +687,6 @@ pam_sm_chauthtok(pam_handle_t *pamh, int + return PAM_SUCCESS; + } else if (off(UNIX__IAMROOT, ctrl) || + (on(UNIX_NIS, ctrl) && _unix_comesfromsource(pamh, user, 0, 1))) { +- /* instruct user what is happening */ +- if (off(UNIX__QUIET, ctrl)) { +- retval = pam_info(pamh, _("Changing password for %s."), user); +- if (retval != PAM_SUCCESS) +- return retval; +- } + retval = pam_get_authtok(pamh, PAM_OLDAUTHTOK, &pass_old, NULL); + + if (retval != PAM_SUCCESS) { diff --git a/pam-1.3.1-noflex.patch b/pam-1.3.1-noflex.patch new file mode 100644 index 0000000000000000000000000000000000000000..c65d225377267448ec4927056930c30c051ac413 --- /dev/null +++ b/pam-1.3.1-noflex.patch @@ -0,0 +1,24 @@ +diff -up Linux-PAM-1.3.1/doc/Makefile.am.noflex Linux-PAM-1.3.1/doc/Makefile.am +--- Linux-PAM-1.3.1/doc/Makefile.am.noflex 2017-02-10 11:10:15.000000000 +0100 ++++ Linux-PAM-1.3.1/doc/Makefile.am 2018-05-18 14:53:50.300997606 +0200 +@@ -2,7 +2,7 @@ + # Copyright (c) 2005, 2006 Thorsten Kukuk + # + +-SUBDIRS = man specs sag adg mwg ++SUBDIRS = man sag adg mwg + + CLEANFILES = *~ + +diff -up Linux-PAM-1.3.1/Makefile.am.noflex Linux-PAM-1.3.1/Makefile.am +--- Linux-PAM-1.3.1/Makefile.am.noflex 2018-05-18 14:53:50.301997629 +0200 ++++ Linux-PAM-1.3.1/Makefile.am 2018-05-18 14:55:31.576353800 +0200 +@@ -4,7 +4,7 @@ + + AUTOMAKE_OPTIONS = 1.9 gnu dist-bzip2 dist-xz check-news + +-SUBDIRS = libpam tests libpamc libpam_misc modules po conf doc examples xtests ++SUBDIRS = libpam tests libpamc libpam_misc modules po doc examples xtests + + CLEANFILES = *~ + diff --git a/pam.spec b/pam.spec new file mode 100644 index 0000000000000000000000000000000000000000..26afc10e4fee2568c7e883fea81d8f73bd3b8e8c --- /dev/null +++ b/pam.spec @@ -0,0 +1,193 @@ +%define _pamlibdir %{_libdir} +%define _moduledir %{_libdir}/security +%define _secconfdir %{_sysconfdir}/security +%define _pamconfdir %{_sysconfdir}/pam.d +Name: pam +Version: 1.3.1 +Release: 6 +Summary: Pluggable Authentication Modules for Linux +License: BSD and GPLv2+ +URL: http://www.linux-pam.org/ +Source0: https://github.com/linux-pam/linux-pam/releases/download/v%{version}/Linux-PAM-%{version}.tar.xz +Source1: https://github.com/linux-pam/linux-pam/releases/download/v%{version}/Linux-PAM-%{version}.tar.xz.asc +Source5: other.pamd +Source6: system-auth.pamd +Source7: password-auth.pamd +Source8: fingerprint-auth.pamd +Source9: smartcard-auth.pamd +Source10: config-util.pamd +Source15: pamtmp.conf +Source16: postlogin.pamd +Source18: https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt +Patch5: pam-1.1.0-notally.patch +Patch6: pam-1.2.1-faillock.patch +Patch7: pam-1.2.1-faillock-admin-group.patch +Patch9: pam-1.3.1-noflex.patch +Patch10: pam-1.1.3-nouserenv.patch +Patch13: pam-1.1.6-limits-user.patch +Patch15: pam-1.1.8-full-relro.patch +Patch20: pam-1.2.0-unix-no-fallback.patch +Patch29: pam-1.3.0-pwhistory-helper.patch +Patch31: pam-1.1.8-audit-user-mgmt.patch +Patch33: pam-1.3.0-unix-nomsg.patch + +Patch6000: bugfix-pam-1.1.8-faillock-failmessages.patch +Patch6001: bugfix-pam-1.1.8-faillock-systemtime.patch +Patch6002: bugfix-pam-1.1.8-mod-chinese-date-format.patch +Patch6003: bugfix-pam-1.1.8-translation-missing-add.patch + +BuildRequires: autoconf automake libtool bison flex sed cracklib-devel +BuildRequires: perl-interpreter pkgconfig gettext-devel libtirpc-devel libnsl2-devel +BuildRequires: audit-libs-devel libselinux-devel libdb-devel +BuildRequires: linuxdoc-tools elinks libxslt docbook-style-xsl docbook-dtds + +Requires: cracklib libpwquality coreutils glibc audit libselinux + +%description +PAM (Pluggable Authentication Modules) is a system of libraries that +handle the authentication tasks of applications (services) on the system. + +%package devel +Summary: Development files for Linux-PAM +Requires: pam = %{version}-%{release} + +%description devel +%{summary}. + +%package help +Summary: Man pages for Linux-PAM +BuildArch: noarch + +%description help +%{summary}. + +%prep +%autosetup -n Linux-PAM-%{version} -p1 +cp %{SOURCE18} . +autoreconf -i + +%build +%configure \ + --disable-rpath \ + --libdir=%{_pamlibdir} \ + --includedir=%{_includedir}/security \ + --disable-static \ + --disable-prelude + +make -C po update-gmo +%make_build + +%install +%make_install + +mkdir -p doc/README.d +for readme in modules/pam_*/README ; do + cp -f ${readme} doc/README.d/README.`dirname ${readme} | sed -e 's@^modules/@@'` +done + +ln -sf pam_sepermit.so $RPM_BUILD_ROOT%{_moduledir}/pam_selinux_permit.so + +rm -rf $RPM_BUILD_ROOT%{_datadir}/doc/Linux-PAM +rm -f $RPM_BUILD_ROOT%{_sysconfdir}/environment + +install -d -m 755 $RPM_BUILD_ROOT%{_pamconfdir} +install -m 644 %{SOURCE5} $RPM_BUILD_ROOT%{_pamconfdir}/other +install -m 644 %{SOURCE6} $RPM_BUILD_ROOT%{_pamconfdir}/system-auth +install -m 644 %{SOURCE7} $RPM_BUILD_ROOT%{_pamconfdir}/password-auth +install -m 644 %{SOURCE8} $RPM_BUILD_ROOT%{_pamconfdir}/fingerprint-auth +install -m 644 %{SOURCE9} $RPM_BUILD_ROOT%{_pamconfdir}/smartcard-auth +install -m 644 %{SOURCE10} $RPM_BUILD_ROOT%{_pamconfdir}/config-util +install -m 644 %{SOURCE16} $RPM_BUILD_ROOT%{_pamconfdir}/postlogin +install -m 600 /dev/null $RPM_BUILD_ROOT%{_secconfdir}/opasswd +install -d -m 755 $RPM_BUILD_ROOT/var/log +install -m 600 /dev/null $RPM_BUILD_ROOT/var/log/tallylog +install -d -m 755 $RPM_BUILD_ROOT/var/run/faillock + +for phase in auth acct passwd session ; do + ln -sf pam_unix.so $RPM_BUILD_ROOT%{_moduledir}/pam_unix_${phase}.so +done + +install -m644 -D %{SOURCE15} $RPM_BUILD_ROOT%{_prefix}/lib/tmpfiles.d/pam.conf + +find $RPM_BUILD_ROOT -type f -name "*.la" -delete -print +rm -fr $RPM_BUILD_ROOT/usr/share/doc/pam + +%find_lang Linux-PAM + +%check +make check + +%post +/sbin/ldconfig +if [ ! -e /var/log/tallylog ] ; then + /usr/bin/install -m 600 /dev/null /var/log/tallylog || : +fi + +%postun -p /sbin/ldconfig + +%files -f Linux-PAM.lang +%defattr(-,root,root) +%license Copyright COPYING gpl-2.0.txt +%doc AUTHORS README ChangeLog NEWS +%doc doc/README.d/ +%dir %{_pamconfdir} +%config(noreplace) %{_pamconfdir}/other +%config(noreplace) %{_pamconfdir}/system-auth +%config(noreplace) %{_pamconfdir}/password-auth +%config(noreplace) %{_pamconfdir}/fingerprint-auth +%config(noreplace) %{_pamconfdir}/smartcard-auth +%config(noreplace) %{_pamconfdir}/config-util +%config(noreplace) %{_pamconfdir}/postlogin +%{_pamlibdir}/libpam.so.* +%{_pamlibdir}/libpamc.so.* +%{_pamlibdir}/libpam_misc.so.* +%attr(4755,root,root) %{_sbindir}/pam_timestamp_check +%attr(4755,root,root) %{_sbindir}/unix_chkpwd +%attr(0700,root,root) %{_sbindir}/unix_update +%{_sbindir}/pam_tally2 +%{_sbindir}/faillock +%{_sbindir}/mkhomedir_helper +%{_sbindir}/pwhistory_helper +%dir %{_moduledir} +%{_moduledir}/pam*.so +%{_moduledir}/pam_filter/ +%dir %{_secconfdir} +%config(noreplace) %{_secconfdir}/access.conf +%config(noreplace) %{_secconfdir}/group.conf +%config(noreplace) %{_secconfdir}/limits.conf +%dir %{_secconfdir}/limits.d +%config(noreplace) %{_secconfdir}/namespace.conf +%dir %{_secconfdir}/namespace.d +%attr(755,root,root) %config(noreplace) %{_secconfdir}/namespace.init +%config(noreplace) %{_secconfdir}/pam_env.conf +%config(noreplace) %{_secconfdir}/time.conf +%config(noreplace) %{_secconfdir}/opasswd +%config(noreplace) %{_secconfdir}/sepermit.conf +%dir /var/run/sepermit +%ghost %verify(not md5 size mtime) /var/log/tallylog +%dir /var/run/faillock +%{_prefix}/lib/tmpfiles.d/pam.conf + +%files devel +%defattr(-,root,root) +%{_includedir}/security +%{_libdir}/libpam.so +%{_libdir}/libpamc.so +%{_libdir}/libpam_misc.so + +%files help +%defattr(-,root,root) +%{_mandir}/man3/* +%{_mandir}/man5/* +%{_mandir}/man8/* + + +%changelog +* Mon Dec 30 2019 openEuler Buildteam - 1.3.1-6 +- Modify man + +* Tue Sep 24 2019 openEuler Buildteam - 1.3.1-5 +- Adjust requires + +* Sat Sep 14 2019 openEuler Buildteam - 1.3.1-4 +- Package init diff --git a/pamtmp.conf b/pamtmp.conf new file mode 100644 index 0000000000000000000000000000000000000000..e94a86078855b273c8f08c55972fe2be0dd27e28 --- /dev/null +++ b/pamtmp.conf @@ -0,0 +1,3 @@ +d /run/console 0755 root root - +d /run/faillock 0755 root root - +d /run/sepermit 0755 root root - diff --git a/password-auth.pamd b/password-auth.pamd new file mode 100644 index 0000000000000000000000000000000000000000..2e01bf90c09550876e155de9520ae750052bad26 --- /dev/null +++ b/password-auth.pamd @@ -0,0 +1,18 @@ +#%PAM-1.0 +# This file is auto-generated. +# User changes will be destroyed the next time authconfig is run. +auth required pam_env.so +auth sufficient pam_unix.so try_first_pass nullok +auth required pam_deny.so + +account required pam_unix.so + +password requisite pam_pwquality.so try_first_pass local_users_only retry=3 authtok_type= +password sufficient pam_unix.so try_first_pass use_authtok nullok sha512 shadow +password required pam_deny.so + +session optional pam_keyinit.so revoke +session required pam_limits.so +-session optional pam_systemd.so +session [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid +session required pam_unix.so diff --git a/postlogin.5 b/postlogin.5 new file mode 100644 index 0000000000000000000000000000000000000000..3a8abcff52c1e60fd8cb9acbf0ae5a62cb6980e6 --- /dev/null +++ b/postlogin.5 @@ -0,0 +1,46 @@ +.TH POSTLOGIN 5 "2010 Dec 22" "Red Hat" "Linux-PAM Manual" +.SH NAME + +postlogin \- Common configuration file for PAMified services + +.SH SYNOPSIS +.B /etc/pam.d/postlogin +.sp 2 +.SH DESCRIPTION + +The purpose of this PAM configuration file is to provide a common +place for all PAM modules which should be called after the stack +configured in +.BR system-auth +or the other common PAM configuration files. + +.sp +The +.BR postlogin +configuration file is included from all individual service configuration +files that provide login service with shell or file access. + +.SH NOTES +The modules in the postlogin configuration file are executed regardless +of the success or failure of the modules in the +.BR system-auth +configuration file. + +.SH BUGS +.sp 2 +Sometimes it would be useful to be able to skip the postlogin modules in +case the substack of the +.BR system-auth +modules failed. Unfortunately the current Linux-PAM library does not +provide any way how to achieve this. + +.SH "SEE ALSO" +pam(8), config-util(5), system-auth(5) + +The three +.BR Linux-PAM +Guides, for +.BR "system administrators" ", " +.BR "module developers" ", " +and +.BR "application developers" ". " diff --git a/postlogin.pamd b/postlogin.pamd new file mode 100644 index 0000000000000000000000000000000000000000..e036f4eca80231c943f2942ebb01ea0e2ca5f267 --- /dev/null +++ b/postlogin.pamd @@ -0,0 +1,7 @@ +#%PAM-1.0 +# This file is auto-generated. +# User changes will be destroyed the next time authconfig is run. + +session [success=1 default=ignore] pam_succeed_if.so service !~ gdm* service !~ su* quiet +session [default=1] pam_lastlog.so nowtmp showfailed +session optional pam_lastlog.so silent noupdate showfailed diff --git a/smartcard-auth.pamd b/smartcard-auth.pamd new file mode 100644 index 0000000000000000000000000000000000000000..e5b57e379b44fd7097da2d3c7ff416958b0ad493 --- /dev/null +++ b/smartcard-auth.pamd @@ -0,0 +1,19 @@ +#%PAM-1.0 +# This file is auto-generated. +# User changes will be destroyed the next time authconfig is run. +auth required pam_env.so +auth [success=done ignore=ignore default=die] pam_pkcs11.so wait_for_card +auth required pam_deny.so + +account required pam_unix.so +account sufficient pam_localuser.so +account sufficient pam_succeed_if.so uid < 500 quiet +account required pam_permit.so + +password optional pam_pkcs11.so + +session optional pam_keyinit.so revoke +session required pam_limits.so +-session optional pam_systemd.so +session [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid +session required pam_unix.so diff --git a/system-auth.5 b/system-auth.5 new file mode 100644 index 0000000000000000000000000000000000000000..c0ca80bf740ef4480a1dd2fbf642c4a8502f5e3a --- /dev/null +++ b/system-auth.5 @@ -0,0 +1,58 @@ +.TH SYSTEM-AUTH 5 "2010 Dec 22" "Red Hat" "Linux-PAM Manual" +.SH NAME + +system-auth \- Common configuration file for PAMified services + +.SH SYNOPSIS +.B /etc/pam.d/system-auth +.B /etc/pam.d/password-auth +.B /etc/pam.d/fingerprint-auth +.B /etc/pam.d/smartcard-auth +.sp 2 +.SH DESCRIPTION + +The purpose of these configuration files are to provide a common +interface for all applications and service daemons calling into +the PAM library. + +.sp +The +.BR system-auth +configuration file is included from nearly all individual service configuration +files with the help of the +.BR substack +directive. + +.sp +The +.BR password-auth +.BR fingerprint-auth +.BR smartcard-auth +configuration files are for applications which handle authentication from +different types of devices via simultaneously running individual conversations +instead of one aggregate conversation. + +.SH NOTES +Previously these common configuration files were included with the help +of the +.BR include +directive. This limited the use of the different action types of modules. +With the use of +.BR substack +directive to include these common configuration files this limitation +no longer applies. + +.SH BUGS +.sp 2 +None known. + +.SH "SEE ALSO" +pam(8), config-util(5), postlogin(5) + +The three +.BR Linux-PAM +Guides, for +.BR "system administrators" ", " +.BR "module developers" ", " +and +.BR "application developers" ". " diff --git a/system-auth.pamd b/system-auth.pamd new file mode 100644 index 0000000000000000000000000000000000000000..2e01bf90c09550876e155de9520ae750052bad26 --- /dev/null +++ b/system-auth.pamd @@ -0,0 +1,18 @@ +#%PAM-1.0 +# This file is auto-generated. +# User changes will be destroyed the next time authconfig is run. +auth required pam_env.so +auth sufficient pam_unix.so try_first_pass nullok +auth required pam_deny.so + +account required pam_unix.so + +password requisite pam_pwquality.so try_first_pass local_users_only retry=3 authtok_type= +password sufficient pam_unix.so try_first_pass use_authtok nullok sha512 shadow +password required pam_deny.so + +session optional pam_keyinit.so revoke +session required pam_limits.so +-session optional pam_systemd.so +session [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid +session required pam_unix.so