commit 0524306b44bdbce14a69edcffab595e517f3122d Author: MSVSphere Packaging Team Date: Fri Mar 29 16:30:28 2024 +0300 import shadow-utils-4.6-22.el8 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..26bd019 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +SOURCES/shadow-4.6.tar.xz diff --git a/.shadow-utils.metadata b/.shadow-utils.metadata new file mode 100644 index 0000000..65c37db --- /dev/null +++ b/.shadow-utils.metadata @@ -0,0 +1 @@ +0b84eb1010fda5edca2a9d1733f9480200e02de6 SOURCES/shadow-4.6.tar.xz diff --git a/SOURCES/gpl-2.0.txt b/SOURCES/gpl-2.0.txt new file mode 100644 index 0000000..d159169 --- /dev/null +++ b/SOURCES/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/SOURCES/shadow-4.1.5.1-default-range.patch b/SOURCES/shadow-4.1.5.1-default-range.patch new file mode 100644 index 0000000..2a9d640 --- /dev/null +++ b/SOURCES/shadow-4.1.5.1-default-range.patch @@ -0,0 +1,36 @@ +Index: shadow-4.5/lib/semanage.c +=================================================================== +--- shadow-4.5.orig/lib/semanage.c ++++ shadow-4.5/lib/semanage.c +@@ -143,6 +143,7 @@ static int semanage_user_mod (semanage_h + goto done; + } + ++#if 0 + ret = semanage_seuser_set_mlsrange (handle, seuser, DEFAULT_SERANGE); + if (ret != 0) { + fprintf (stderr, +@@ -150,6 +151,7 @@ static int semanage_user_mod (semanage_h + ret = 1; + goto done; + } ++#endif + + ret = semanage_seuser_set_sename (handle, seuser, seuser_name); + if (ret != 0) { +@@ -200,6 +202,7 @@ static int semanage_user_add (semanage_h + goto done; + } + ++#if 0 + ret = semanage_seuser_set_mlsrange (handle, seuser, DEFAULT_SERANGE); + if (ret != 0) { + fprintf (stderr, +@@ -208,6 +211,7 @@ static int semanage_user_add (semanage_h + ret = 1; + goto done; + } ++#endif + + ret = semanage_seuser_set_sename (handle, seuser, seuser_name); + if (ret != 0) { diff --git a/SOURCES/shadow-4.1.5.1-info-parent-dir.patch b/SOURCES/shadow-4.1.5.1-info-parent-dir.patch new file mode 100644 index 0000000..b3a525b --- /dev/null +++ b/SOURCES/shadow-4.1.5.1-info-parent-dir.patch @@ -0,0 +1,21 @@ +Index: shadow-4.5/man/newusers.8.xml +=================================================================== +--- shadow-4.5.orig/man/newusers.8.xml ++++ shadow-4.5/man/newusers.8.xml +@@ -218,7 +218,15 @@ + + If this field does not specify an existing directory, the + specified directory is created, with ownership set to the +- user being created or updated and its primary group. ++ user being created or updated and its primary group. Note ++ that newusers does not create parent directories of the new ++ user's home directory. The newusers command will fail to ++ create the home directory if the parent directories do not ++ exist, and will send a message to stderr informing the user ++ of the failure. The newusers command will not halt or return ++ a failure to the calling shell if it fails to create the home ++ directory, it will continue to process the batch of new users ++ specified. + + + If the home directory of an existing user is changed, diff --git a/SOURCES/shadow-4.1.5.1-logmsg.patch b/SOURCES/shadow-4.1.5.1-logmsg.patch new file mode 100644 index 0000000..ca7e57b --- /dev/null +++ b/SOURCES/shadow-4.1.5.1-logmsg.patch @@ -0,0 +1,13 @@ +Index: shadow-4.5/src/useradd.c +=================================================================== +--- shadow-4.5.orig/src/useradd.c ++++ shadow-4.5/src/useradd.c +@@ -323,7 +323,7 @@ static void fail_exit (int code) + user_name, AUDIT_NO_ID, + SHADOW_AUDIT_FAILURE); + #endif +- SYSLOG ((LOG_INFO, "failed adding user '%s', data deleted", user_name)); ++ SYSLOG ((LOG_INFO, "failed adding user '%s', exit code: %d", user_name, code)); + exit (code); + } + diff --git a/SOURCES/shadow-4.1.5.1-userdel-helpfix.patch b/SOURCES/shadow-4.1.5.1-userdel-helpfix.patch new file mode 100644 index 0000000..075f482 --- /dev/null +++ b/SOURCES/shadow-4.1.5.1-userdel-helpfix.patch @@ -0,0 +1,16 @@ +Index: shadow-4.5/src/userdel.c +=================================================================== +--- shadow-4.5.orig/src/userdel.c ++++ shadow-4.5/src/userdel.c +@@ -143,8 +143,9 @@ static void usage (int status) + "\n" + "Options:\n"), + Prog); +- (void) fputs (_(" -f, --force force removal of files,\n" +- " even if not owned by user\n"), ++ (void) fputs (_(" -f, --force force some actions that would fail otherwise\n" ++ " e.g. removal of user still logged in\n" ++ " or files, even if not owned by the user\n"), + usageout); + (void) fputs (_(" -h, --help display this help message and exit\n"), usageout); + (void) fputs (_(" -r, --remove remove home directory and mail spool\n"), usageout); diff --git a/SOURCES/shadow-4.2.1-date-parsing.patch b/SOURCES/shadow-4.2.1-date-parsing.patch new file mode 100644 index 0000000..2a798d0 --- /dev/null +++ b/SOURCES/shadow-4.2.1-date-parsing.patch @@ -0,0 +1,69 @@ +Index: shadow-4.5/libmisc/getdate.y +=================================================================== +--- shadow-4.5.orig/libmisc/getdate.y ++++ shadow-4.5/libmisc/getdate.y +@@ -152,6 +152,7 @@ static int yyHaveDay; + static int yyHaveRel; + static int yyHaveTime; + static int yyHaveZone; ++static int yyHaveYear; + static int yyTimezone; + static int yyDay; + static int yyHour; +@@ -293,18 +294,21 @@ date : tUNUMBER '/' tUNUMBER { + yyDay = $3; + yyYear = $5; + } ++ yyHaveYear++; + } + | tUNUMBER tSNUMBER tSNUMBER { + /* ISO 8601 format. yyyy-mm-dd. */ + yyYear = $1; + yyMonth = -$2; + yyDay = -$3; ++ yyHaveYear++; + } + | tUNUMBER tMONTH tSNUMBER { + /* e.g. 17-JUN-1992. */ + yyDay = $1; + yyMonth = $2; + yyYear = -$3; ++ yyHaveYear++; + } + | tMONTH tUNUMBER { + yyMonth = $1; +@@ -314,6 +318,7 @@ date : tUNUMBER '/' tUNUMBER { + yyMonth = $1; + yyDay = $2; + yyYear = $4; ++ yyHaveYear++; + } + | tUNUMBER tMONTH { + yyMonth = $2; +@@ -323,6 +328,7 @@ date : tUNUMBER '/' tUNUMBER { + yyMonth = $2; + yyDay = $1; + yyYear = $3; ++ yyHaveYear++; + } + ; + +@@ -395,7 +401,8 @@ relunit : tUNUMBER tYEAR_UNIT { + + number : tUNUMBER + { +- if ((yyHaveTime != 0) && (yyHaveDate != 0) && (yyHaveRel == 0)) ++ if ((yyHaveTime != 0 || $1 >= 100) && !yyHaveYear ++ && (yyHaveDate != 0) && (yyHaveRel == 0)) + yyYear = $1; + else + { +@@ -802,7 +809,7 @@ yylex (void) + return LookupWord (buff); + } + if (c != '(') +- return *yyInput++; ++ return (unsigned char)*yyInput++; + Count = 0; + do + { diff --git a/SOURCES/shadow-4.2.1-no-lock-dos.patch b/SOURCES/shadow-4.2.1-no-lock-dos.patch new file mode 100644 index 0000000..c6873e9 --- /dev/null +++ b/SOURCES/shadow-4.2.1-no-lock-dos.patch @@ -0,0 +1,16 @@ +Index: shadow-4.5/lib/commonio.c +=================================================================== +--- shadow-4.5.orig/lib/commonio.c ++++ shadow-4.5/lib/commonio.c +@@ -140,7 +140,10 @@ static int do_lock_file (const char *fil + int retval; + char buf[32]; + +- fd = open (file, O_CREAT | O_EXCL | O_WRONLY, 0600); ++ /* We depend here on the fact, that the file name is pid-specific. ++ * So no O_EXCL here and no DoS. ++ */ ++ fd = open (file, O_CREAT | O_TRUNC | O_WRONLY, 0600); + if (-1 == fd) { + if (log) { + (void) fprintf (stderr, diff --git a/SOURCES/shadow-4.2.1-null-tm.patch b/SOURCES/shadow-4.2.1-null-tm.patch new file mode 100644 index 0000000..b1dd1c4 --- /dev/null +++ b/SOURCES/shadow-4.2.1-null-tm.patch @@ -0,0 +1,91 @@ +Index: shadow-4.5/src/faillog.c +=================================================================== +--- shadow-4.5.orig/src/faillog.c ++++ shadow-4.5/src/faillog.c +@@ -163,10 +163,14 @@ static void print_one (/*@null@*/const s + } + + tm = localtime (&fl.fail_time); ++ if (tm == NULL) { ++ cp = "(unknown)"; ++ } else { + #ifdef HAVE_STRFTIME +- strftime (ptime, sizeof (ptime), "%D %H:%M:%S %z", tm); +- cp = ptime; ++ strftime (ptime, sizeof (ptime), "%D %H:%M:%S %z", tm); ++ cp = ptime; + #endif ++ } + printf ("%-9s %5d %5d ", + pw->pw_name, fl.fail_cnt, fl.fail_max); + /* FIXME: cp is not defined ifndef HAVE_STRFTIME */ +Index: shadow-4.5/src/chage.c +=================================================================== +--- shadow-4.5.orig/src/chage.c ++++ shadow-4.5/src/chage.c +@@ -168,6 +168,10 @@ static void date_to_str (char *buf, size + struct tm *tp; + + tp = gmtime (&date); ++ if (tp == NULL) { ++ (void) snprintf (buf, maxsize, "(unknown)"); ++ return; ++ } + #ifdef HAVE_STRFTIME + (void) strftime (buf, maxsize, "%Y-%m-%d", tp); + #else +Index: shadow-4.5/src/lastlog.c +=================================================================== +--- shadow-4.5.orig/src/lastlog.c ++++ shadow-4.5/src/lastlog.c +@@ -158,13 +158,17 @@ static void print_one (/*@null@*/const s + + ll_time = ll.ll_time; + tm = localtime (&ll_time); ++ if (tm == NULL) { ++ cp = "(unknown)"; ++ } else { + #ifdef HAVE_STRFTIME +- strftime (ptime, sizeof (ptime), "%a %b %e %H:%M:%S %z %Y", tm); +- cp = ptime; ++ strftime (ptime, sizeof (ptime), "%a %b %e %H:%M:%S %z %Y", tm); ++ cp = ptime; + #else +- cp = asctime (tm); +- cp[24] = '\0'; ++ cp = asctime (tm); ++ cp[24] = '\0'; + #endif ++ } + + if (ll.ll_time == (time_t) 0) { + cp = _("**Never logged in**\0"); +Index: shadow-4.5/src/passwd.c +=================================================================== +--- shadow-4.5.orig/src/passwd.c ++++ shadow-4.5/src/passwd.c +@@ -455,6 +455,9 @@ static /*@observer@*/const char *date_to + struct tm *tm; + + tm = gmtime (&t); ++ if (tm == NULL) { ++ return "(unknown)"; ++ } + #ifdef HAVE_STRFTIME + (void) strftime (buf, sizeof buf, "%m/%d/%Y", tm); + #else /* !HAVE_STRFTIME */ +Index: shadow-4.5/src/usermod.c +=================================================================== +--- shadow-4.5.orig/src/usermod.c ++++ shadow-4.5/src/usermod.c +@@ -210,6 +210,10 @@ static void date_to_str (/*@unique@*//*@ + } else { + time_t t = (time_t) date; + tp = gmtime (&t); ++ if (tp == NULL) { ++ strncpy (buf, "unknown", maxsize); ++ return; ++ } + #ifdef HAVE_STRFTIME + strftime (buf, maxsize, "%Y-%m-%d", tp); + #else diff --git a/SOURCES/shadow-4.5-crypt_h.patch b/SOURCES/shadow-4.5-crypt_h.patch new file mode 100644 index 0000000..c8d19e4 --- /dev/null +++ b/SOURCES/shadow-4.5-crypt_h.patch @@ -0,0 +1,41 @@ +Index: shadow-4.5/configure.ac +=================================================================== +--- shadow-4.5.orig/configure.ac ++++ shadow-4.5/configure.ac +@@ -32,9 +32,9 @@ AC_HEADER_STDC + AC_HEADER_SYS_WAIT + AC_HEADER_STDBOOL + +-AC_CHECK_HEADERS(errno.h fcntl.h limits.h unistd.h sys/time.h utmp.h \ +- utmpx.h termios.h termio.h sgtty.h sys/ioctl.h syslog.h paths.h \ +- utime.h ulimit.h sys/resource.h gshadow.h lastlog.h \ ++AC_CHECK_HEADERS(crypt.h errno.h fcntl.h limits.h unistd.h sys/time.h \ ++ utmp.h utmpx.h termios.h termio.h sgtty.h sys/ioctl.h syslog.h \ ++ paths.h utime.h ulimit.h sys/resource.h gshadow.h lastlog.h \ + locale.h rpc/key_prot.h netdb.h acl/libacl.h attr/libattr.h \ + attr/error_context.h) + +Index: shadow-4.5/lib/defines.h +=================================================================== +--- shadow-4.5.orig/lib/defines.h ++++ shadow-4.5/lib/defines.h +@@ -4,6 +4,8 @@ + #ifndef _DEFINES_H_ + #define _DEFINES_H_ + ++#include "config.h" ++ + #if HAVE_STDBOOL_H + # include + #else +@@ -94,6 +96,10 @@ char *strchr (), *strrchr (), *strtok () + # include + #endif + ++#if HAVE_CRYPT_H ++# include /* crypt(3) may be defined in here */ ++#endif ++ + #if TIME_WITH_SYS_TIME + # include + # include diff --git a/SOURCES/shadow-4.5-long-entry.patch b/SOURCES/shadow-4.5-long-entry.patch new file mode 100644 index 0000000..8670e75 --- /dev/null +++ b/SOURCES/shadow-4.5-long-entry.patch @@ -0,0 +1,84 @@ +diff -up shadow-4.5/lib/defines.h.long-entry shadow-4.5/lib/defines.h +--- shadow-4.5/lib/defines.h.long-entry 2014-09-01 16:36:40.000000000 +0200 ++++ shadow-4.5/lib/defines.h 2018-04-20 11:53:07.419308212 +0200 +@@ -382,4 +382,7 @@ extern char *strerror (); + # endif + #endif + ++/* Maximum length of passwd entry */ ++#define PASSWD_ENTRY_MAX_LENGTH 32768 ++ + #endif /* _DEFINES_H_ */ +diff -up shadow-4.5/lib/pwio.c.long-entry shadow-4.5/lib/pwio.c +--- shadow-4.5/lib/pwio.c.long-entry 2015-11-17 17:45:15.000000000 +0100 ++++ shadow-4.5/lib/pwio.c 2018-04-20 12:10:24.400837235 +0200 +@@ -79,7 +79,10 @@ static int passwd_put (const void *ent, + || (pw->pw_gid == (gid_t)-1) + || (valid_field (pw->pw_gecos, ":\n") == -1) + || (valid_field (pw->pw_dir, ":\n") == -1) +- || (valid_field (pw->pw_shell, ":\n") == -1)) { ++ || (valid_field (pw->pw_shell, ":\n") == -1) ++ || (strlen (pw->pw_name) + strlen (pw->pw_passwd) + ++ strlen (pw->pw_gecos) + strlen (pw->pw_dir) + ++ strlen (pw->pw_shell) + 100 > PASSWD_ENTRY_MAX_LENGTH)) { + return -1; + } + +diff -up shadow-4.5/lib/sgetpwent.c.long-entry shadow-4.5/lib/sgetpwent.c +--- shadow-4.5/lib/sgetpwent.c.long-entry 2014-09-01 16:36:40.000000000 +0200 ++++ shadow-4.5/lib/sgetpwent.c 2018-04-20 12:16:31.911513808 +0200 +@@ -57,7 +57,7 @@ + struct passwd *sgetpwent (const char *buf) + { + static struct passwd pwent; +- static char pwdbuf[1024]; ++ static char pwdbuf[PASSWD_ENTRY_MAX_LENGTH]; + register int i; + register char *cp; + char *fields[NFIELDS]; +@@ -67,8 +67,10 @@ struct passwd *sgetpwent (const char *bu + * the password structure remain valid. + */ + +- if (strlen (buf) >= sizeof pwdbuf) ++ if (strlen (buf) >= sizeof pwdbuf) { ++ fprintf (stderr, "Too long passwd entry encountered, file corruption?\n"); + return 0; /* fail if too long */ ++ } + strcpy (pwdbuf, buf); + + /* +diff -up shadow-4.5/lib/sgetspent.c.long-entry shadow-4.5/lib/sgetspent.c +--- shadow-4.5/lib/sgetspent.c.long-entry 2014-09-01 16:36:40.000000000 +0200 ++++ shadow-4.5/lib/sgetspent.c 2018-04-20 12:16:54.505056257 +0200 +@@ -48,7 +48,7 @@ + */ + struct spwd *sgetspent (const char *string) + { +- static char spwbuf[1024]; ++ static char spwbuf[PASSWD_ENTRY_MAX_LENGTH]; + static struct spwd spwd; + char *fields[FIELDS]; + char *cp; +@@ -61,6 +61,7 @@ struct spwd *sgetspent (const char *stri + */ + + if (strlen (string) >= sizeof spwbuf) { ++ fprintf (stderr, "Too long shadow entry encountered, file corruption?\n"); + return 0; /* fail if too long */ + } + strcpy (spwbuf, string); +diff -up shadow-4.5/lib/shadowio.c.long-entry shadow-4.5/lib/shadowio.c +--- shadow-4.5/lib/shadowio.c.long-entry 2016-12-07 06:30:41.000000001 +0100 ++++ shadow-4.5/lib/shadowio.c 2018-04-20 12:12:03.292171667 +0200 +@@ -79,7 +79,9 @@ static int shadow_put (const void *ent, + + if ( (NULL == sp) + || (valid_field (sp->sp_namp, ":\n") == -1) +- || (valid_field (sp->sp_pwdp, ":\n") == -1)) { ++ || (valid_field (sp->sp_pwdp, ":\n") == -1) ++ || (strlen (sp->sp_namp) + strlen (sp->sp_pwdp) + ++ 1000 > PASSWD_ENTRY_MAX_LENGTH)) { + return -1; + } + diff --git a/SOURCES/shadow-4.5-usermod-unlock.patch b/SOURCES/shadow-4.5-usermod-unlock.patch new file mode 100644 index 0000000..e2d70b5 --- /dev/null +++ b/SOURCES/shadow-4.5-usermod-unlock.patch @@ -0,0 +1,64 @@ +Index: shadow-4.5/src/usermod.c +=================================================================== +--- shadow-4.5.orig/src/usermod.c ++++ shadow-4.5/src/usermod.c +@@ -455,14 +455,17 @@ static char *new_pw_passwd (char *pw_pas + strcat (buf, pw_pass); + pw_pass = buf; + } else if (Uflg && pw_pass[0] == '!') { +- char *s; ++ char *s = pw_pass; + +- if (pw_pass[1] == '\0') { ++ while ('!' == *s) ++ ++s; ++ ++ if (*s == '\0') { + fprintf (stderr, + _("%s: unlocking the user's password would result in a passwordless account.\n" + "You should set a password with usermod -p to unlock this user's password.\n"), + Prog); +- return pw_pass; ++ return NULL; + } + + #ifdef WITH_AUDIT +@@ -471,12 +474,15 @@ static char *new_pw_passwd (char *pw_pas + user_newname, (unsigned int) user_newid, 1); + #endif + SYSLOG ((LOG_INFO, "unlock user '%s' password", user_newname)); +- s = pw_pass; +- while ('\0' != *s) { +- *s = *(s + 1); +- s++; +- } ++ memmove (pw_pass, s, strlen (s) + 1); + } else if (pflg) { ++ if (strchr (user_pass, ':') != NULL) { ++ fprintf (stderr, ++ _("%s: The password field cannot contain a colon character.\n"), ++ Prog); ++ return NULL; ++ ++ } + #ifdef WITH_AUDIT + audit_logger (AUDIT_USER_CHAUTHTOK, Prog, + "updating-password", +@@ -525,6 +531,8 @@ static void new_pwent (struct passwd *pw + if ( (!is_shadow_pwd) + || (strcmp (pwent->pw_passwd, SHADOW_PASSWD_STRING) != 0)) { + pwent->pw_passwd = new_pw_passwd (pwent->pw_passwd); ++ if (pwent->pw_passwd == NULL) ++ fail_exit (E_PW_UPDATE); + } + + if (uflg) { +@@ -639,6 +647,8 @@ static void new_spent (struct spwd *spen + * + aging has been requested + */ + spent->sp_pwdp = new_pw_passwd (spent->sp_pwdp); ++ if (spent->sp_pwdp == NULL) ++ fail_exit(E_PW_UPDATE); + + if (pflg) { + spent->sp_lstchg = (long) gettime () / SCALE; diff --git a/SOURCES/shadow-4.6-audit-update.patch b/SOURCES/shadow-4.6-audit-update.patch new file mode 100644 index 0000000..4237739 --- /dev/null +++ b/SOURCES/shadow-4.6-audit-update.patch @@ -0,0 +1,2365 @@ +diff -up shadow-4.6/libmisc/audit_help.c.audit-update shadow-4.6/libmisc/audit_help.c +--- shadow-4.6/libmisc/audit_help.c.audit-update 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/libmisc/audit_help.c 2018-05-28 15:01:09.913717564 +0200 +@@ -68,7 +68,7 @@ void audit_help_open (void) + * This function will log a message to the audit system using a predefined + * message format. Parameter usage is as follows: + * +- * type - type of message: AUDIT_USER_CHAUTHTOK for changing any account ++ * type - type of message: AUDIT_USER_MGMT for changing any account + * attributes. + * pgname - program's name + * op - operation. "adding user", "changing finger info", "deleting group" +@@ -88,6 +88,39 @@ void audit_logger (int type, unused cons + } + } + ++/* ++ * This function will log a message to the audit system using a predefined ++ * message format. Parameter usage is as follows: ++ * ++ * type - type of message: AUDIT_USER_MGMT for changing any account ++ * attributes. ++ * pgname - program's name ++ * op - operation. "adding user", "changing finger info", "deleting group" ++ * name - user's account or group name. If not available use NULL. ++ * id - uid or gid that the operation is being performed on. This is used ++ * only when user is NULL. ++ * grp - group name associated with event ++ */ ++void audit_logger_with_group (int type, unused const char *pgname, ++ const char *op, const char *name, unsigned int id, ++ const char *grp, shadow_audit_result result) ++{ ++ int len; ++ char enc_group[(GROUP_NAME_MAX_LENGTH*2)+1], buf[1024]; ++ if (audit_fd < 0) { ++ return; ++ } ++ len = strnlen(grp, sizeof(enc_group)/2); ++ if (audit_value_needs_encoding(grp, len)) { ++ snprintf(buf, sizeof(buf), "%s grp=%s", op, ++ audit_encode_value(enc_group, grp, len)); ++ } else { ++ snprintf(buf, sizeof(buf), "%s grp=\"%s\"", op, grp); ++ } ++ audit_log_acct_message (audit_fd, type, NULL, buf, name, id, ++ NULL, NULL, NULL, (int) result); ++} ++ + void audit_logger_message (const char *message, shadow_audit_result result) + { + if (audit_fd < 0) { +diff -up shadow-4.6/libmisc/cleanup_group.c.audit-update shadow-4.6/libmisc/cleanup_group.c +--- shadow-4.6/libmisc/cleanup_group.c.audit-update 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/libmisc/cleanup_group.c 2018-05-28 15:01:09.913717564 +0200 +@@ -83,7 +83,7 @@ void cleanup_report_mod_group (void *cle + gr_dbname (), + info->action)); + #ifdef WITH_AUDIT +- audit_logger (AUDIT_USER_ACCT, Prog, ++ audit_logger (AUDIT_GRP_MGMT, Prog, + info->audit_msg, + info->name, AUDIT_NO_ID, + SHADOW_AUDIT_FAILURE); +@@ -101,7 +101,7 @@ void cleanup_report_mod_gshadow (void *c + sgr_dbname (), + info->action)); + #ifdef WITH_AUDIT +- audit_logger (AUDIT_USER_ACCT, Prog, ++ audit_logger (AUDIT_GRP_MGMT, Prog, + info->audit_msg, + info->name, AUDIT_NO_ID, + SHADOW_AUDIT_FAILURE); +@@ -122,7 +122,7 @@ void cleanup_report_add_group_group (voi + SYSLOG ((LOG_ERR, "failed to add group %s to %s", name, gr_dbname ())); + #ifdef WITH_AUDIT + audit_logger (AUDIT_ADD_GROUP, Prog, +- "adding group to /etc/group", ++ "adding-group", + name, AUDIT_NO_ID, + SHADOW_AUDIT_FAILURE); + #endif +@@ -141,8 +141,8 @@ void cleanup_report_add_group_gshadow (v + + SYSLOG ((LOG_ERR, "failed to add group %s to %s", name, sgr_dbname ())); + #ifdef WITH_AUDIT +- audit_logger (AUDIT_ADD_GROUP, Prog, +- "adding group to /etc/gshadow", ++ audit_logger (AUDIT_GRP_MGMT, Prog, ++ "adding-shadow-group", + name, AUDIT_NO_ID, + SHADOW_AUDIT_FAILURE); + #endif +@@ -164,8 +164,8 @@ void cleanup_report_del_group_group (voi + "failed to remove group %s from %s", + name, gr_dbname ())); + #ifdef WITH_AUDIT +- audit_logger (AUDIT_ADD_GROUP, Prog, +- "removing group from /etc/group", ++ audit_logger (AUDIT_DEL_GROUP, Prog, ++ "removing-group", + name, AUDIT_NO_ID, + SHADOW_AUDIT_FAILURE); + #endif +@@ -187,8 +187,8 @@ void cleanup_report_del_group_gshadow (v + "failed to remove group %s from %s", + name, sgr_dbname ())); + #ifdef WITH_AUDIT +- audit_logger (AUDIT_ADD_GROUP, Prog, +- "removing group from /etc/gshadow", ++ audit_logger (AUDIT_GRP_MGMT, Prog, ++ "removing-shadow-group", + name, AUDIT_NO_ID, + SHADOW_AUDIT_FAILURE); + #endif +@@ -208,7 +208,7 @@ void cleanup_unlock_group (unused void * + Prog, gr_dbname ()); + SYSLOG ((LOG_ERR, "failed to unlock %s", gr_dbname ())); + #ifdef WITH_AUDIT +- audit_logger_message ("unlocking group file", ++ audit_logger_message ("unlocking-group", + SHADOW_AUDIT_FAILURE); + #endif + } +@@ -228,7 +228,7 @@ void cleanup_unlock_gshadow (unused void + Prog, sgr_dbname ()); + SYSLOG ((LOG_ERR, "failed to unlock %s", sgr_dbname ())); + #ifdef WITH_AUDIT +- audit_logger_message ("unlocking gshadow file", ++ audit_logger_message ("unlocking-gshadow", + SHADOW_AUDIT_FAILURE); + #endif + } +diff -up shadow-4.6/libmisc/cleanup_user.c.audit-update shadow-4.6/libmisc/cleanup_user.c +--- shadow-4.6/libmisc/cleanup_user.c.audit-update 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/libmisc/cleanup_user.c 2018-05-28 15:01:09.913717564 +0200 +@@ -65,7 +65,7 @@ void cleanup_report_mod_passwd (void *cl + pw_dbname (), + info->action)); + #ifdef WITH_AUDIT +- audit_logger (AUDIT_USER_ACCT, Prog, ++ audit_logger (AUDIT_USER_MGMT, Prog, + info->audit_msg, + info->name, AUDIT_NO_ID, + SHADOW_AUDIT_FAILURE); +@@ -86,7 +86,7 @@ void cleanup_report_add_user_passwd (voi + SYSLOG ((LOG_ERR, "failed to add user %s to %s", name, pw_dbname ())); + #ifdef WITH_AUDIT + audit_logger (AUDIT_ADD_USER, Prog, +- "adding user to /etc/passwd", ++ "adding-user", + name, AUDIT_NO_ID, + SHADOW_AUDIT_FAILURE); + #endif +@@ -105,8 +105,8 @@ void cleanup_report_add_user_shadow (voi + + SYSLOG ((LOG_ERR, "failed to add user %s to %s", name, spw_dbname ())); + #ifdef WITH_AUDIT +- audit_logger (AUDIT_ADD_USER, Prog, +- "adding user to /etc/shadow", ++ audit_logger (AUDIT_USER_MGMT, Prog, ++ "adding-shadow-user", + name, AUDIT_NO_ID, + SHADOW_AUDIT_FAILURE); + #endif +@@ -125,7 +125,7 @@ void cleanup_unlock_passwd (unused void + Prog, pw_dbname ()); + SYSLOG ((LOG_ERR, "failed to unlock %s", pw_dbname ())); + #ifdef WITH_AUDIT +- audit_logger_message ("unlocking passwd file", ++ audit_logger_message ("unlocking-passwd", + SHADOW_AUDIT_FAILURE); + #endif + } +@@ -144,7 +144,7 @@ void cleanup_unlock_shadow (unused void + Prog, spw_dbname ()); + SYSLOG ((LOG_ERR, "failed to unlock %s", spw_dbname ())); + #ifdef WITH_AUDIT +- audit_logger_message ("unlocking shadow file", ++ audit_logger_message ("unlocking-shadow", + SHADOW_AUDIT_FAILURE); + #endif + } +diff -up shadow-4.6/lib/prototypes.h.audit-update shadow-4.6/lib/prototypes.h +--- shadow-4.6/lib/prototypes.h.audit-update 2018-05-28 15:01:09.901717309 +0200 ++++ shadow-4.6/lib/prototypes.h 2018-05-28 15:01:09.913717564 +0200 +@@ -211,12 +211,21 @@ extern int audit_fd; + extern void audit_help_open (void); + /* Use AUDIT_NO_ID when a name is provided to audit_logger instead of an ID */ + #define AUDIT_NO_ID ((unsigned int) -1) ++#ifndef AUDIT_GRP_MGMT ++#define AUDIT_GRP_MGMT 1132 /* Group account was modified */ ++#endif ++#ifndef AUDIT_GRP_CHAUTHTOK ++#define AUDIT_GRP_CHAUTHTOK 1133 /* Group account password was changed */ ++#endif + typedef enum { + SHADOW_AUDIT_FAILURE = 0, + SHADOW_AUDIT_SUCCESS = 1} shadow_audit_result; + extern void audit_logger (int type, const char *pgname, const char *op, + const char *name, unsigned int id, + shadow_audit_result result); ++void audit_logger_with_group (int type, unused const char *pgname, ++ const char *op, const char *name, unsigned int id, ++ const char *grp, shadow_audit_result result); + void audit_logger_message (const char *message, shadow_audit_result result); + #endif + +diff -up shadow-4.6/src/gpasswd.c.audit-update shadow-4.6/src/gpasswd.c +--- shadow-4.6/src/gpasswd.c.audit-update 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/src/gpasswd.c 2018-05-28 15:01:09.914717585 +0200 +@@ -137,7 +137,7 @@ static void usage (int status) + (void) fputs (_(" -d, --delete USER remove USER from GROUP\n"), usageout); + (void) fputs (_(" -h, --help display this help message and exit\n"), usageout); + (void) fputs (_(" -Q, --root CHROOT_DIR directory to chroot into\n"), usageout); +- (void) fputs (_(" -r, --remove-password remove the GROUP's password\n"), usageout); ++ (void) fputs (_(" -r, --delete-password remove the GROUP's password\n"), usageout); + (void) fputs (_(" -R, --restrict restrict access to GROUP to its members\n"), usageout); + (void) fputs (_(" -M, --members USER,... set the list of members of GROUP\n"), usageout); + #ifdef SHADOWGRP +@@ -396,21 +396,14 @@ static void open_files (void) + + static void log_gpasswd_failure (const char *suffix) + { +-#ifdef WITH_AUDIT +- char buf[1024]; +-#endif + if (aflg) { + SYSLOG ((LOG_ERR, + "%s failed to add user %s to group %s%s", + myname, user, group, suffix)); + #ifdef WITH_AUDIT +- snprintf (buf, 1023, +- "%s failed to add user %s to group %s%s", +- myname, user, group, suffix); +- buf[1023] = '\0'; +- audit_logger (AUDIT_USER_ACCT, Prog, +- buf, +- group, AUDIT_NO_ID, ++ audit_logger_with_group (AUDIT_USER_MGMT, Prog, ++ "add-user-to-group", ++ user, AUDIT_NO_ID, group, + SHADOW_AUDIT_FAILURE); + #endif + } else if (dflg) { +@@ -418,13 +411,9 @@ static void log_gpasswd_failure (const c + "%s failed to remove user %s from group %s%s", + myname, user, group, suffix)); + #ifdef WITH_AUDIT +- snprintf (buf, 1023, +- "%s failed to remove user %s from group %s%s", +- myname, user, group, suffix); +- buf[1023] = '\0'; +- audit_logger (AUDIT_USER_ACCT, Prog, +- buf, +- group, AUDIT_NO_ID, ++ audit_logger_with_group (AUDIT_USER_MGMT, Prog, ++ "delete-user-from-group", ++ user, AUDIT_NO_ID, group, + SHADOW_AUDIT_FAILURE); + #endif + } else if (rflg) { +@@ -432,13 +421,9 @@ static void log_gpasswd_failure (const c + "%s failed to remove password of group %s%s", + myname, group, suffix)); + #ifdef WITH_AUDIT +- snprintf (buf, 1023, +- "%s failed to remove password of group %s%s", +- myname, group, suffix); +- buf[1023] = '\0'; +- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, +- buf, +- group, AUDIT_NO_ID, ++ audit_logger_with_group (AUDIT_GRP_CHAUTHTOK, Prog, ++ "delete-group-password", ++ myname, AUDIT_NO_ID, group, + SHADOW_AUDIT_FAILURE); + #endif + } else if (Rflg) { +@@ -446,13 +431,9 @@ static void log_gpasswd_failure (const c + "%s failed to restrict access to group %s%s", + myname, group, suffix)); + #ifdef WITH_AUDIT +- snprintf (buf, 1023, +- "%s failed to restrict access to group %s%s", +- myname, group, suffix); +- buf[1023] = '\0'; +- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, +- buf, +- group, AUDIT_NO_ID, ++ audit_logger_with_group (AUDIT_GRP_MGMT, Prog, ++ "restrict-group", ++ myname, AUDIT_NO_ID, group, + SHADOW_AUDIT_FAILURE); + #endif + } else if (Aflg || Mflg) { +@@ -462,13 +443,9 @@ static void log_gpasswd_failure (const c + "%s failed to set the administrators of group %s to %s%s", + myname, group, admins, suffix)); + #ifdef WITH_AUDIT +- snprintf (buf, 1023, +- "%s failed to set the administrators of group %s to %s%s", +- myname, group, admins, suffix); +- buf[1023] = '\0'; +- audit_logger (AUDIT_USER_ACCT, Prog, +- buf, +- group, AUDIT_NO_ID, ++ audit_logger_with_group (AUDIT_GRP_MGMT, Prog, ++ "set-admins-of-group", ++ admins, AUDIT_NO_ID, group, + SHADOW_AUDIT_FAILURE); + #endif + } +@@ -478,13 +455,9 @@ static void log_gpasswd_failure (const c + "%s failed to set the members of group %s to %s%s", + myname, group, members, suffix)); + #ifdef WITH_AUDIT +- snprintf (buf, 1023, +- "%s failed to set the members of group %s to %s%s", +- myname, group, members, suffix); +- buf[1023] = '\0'; +- audit_logger (AUDIT_USER_ACCT, Prog, +- buf, +- group, AUDIT_NO_ID, ++ audit_logger_with_group (AUDIT_USER_MGMT, Prog, ++ "add-users-to-group", ++ members, AUDIT_NO_ID, group, + SHADOW_AUDIT_FAILURE); + #endif + } +@@ -493,13 +466,9 @@ static void log_gpasswd_failure (const c + "%s failed to change password of group %s%s", + myname, group, suffix)); + #ifdef WITH_AUDIT +- snprintf (buf, 1023, +- "%s failed to change password of group %s%s", +- myname, group, suffix); +- buf[1023] = '\0'; +- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, +- buf, +- group, AUDIT_NO_ID, ++ audit_logger_with_group (AUDIT_GRP_CHAUTHTOK, Prog, ++ "change-password", ++ myname, AUDIT_NO_ID, group, + SHADOW_AUDIT_FAILURE); + #endif + } +@@ -530,21 +499,14 @@ static void log_gpasswd_failure_gshadow + + static void log_gpasswd_success (const char *suffix) + { +-#ifdef WITH_AUDIT +- char buf[1024]; +-#endif + if (aflg) { + SYSLOG ((LOG_INFO, + "user %s added by %s to group %s%s", + user, myname, group, suffix)); + #ifdef WITH_AUDIT +- snprintf (buf, 1023, +- "user %s added by %s to group %s%s", +- user, myname, group, suffix); +- buf[1023] = '\0'; +- audit_logger (AUDIT_USER_ACCT, Prog, +- buf, +- group, AUDIT_NO_ID, ++ audit_logger_with_group (AUDIT_USER_MGMT, Prog, ++ "add-user-to-group", ++ user, AUDIT_NO_ID, group, + SHADOW_AUDIT_SUCCESS); + #endif + } else if (dflg) { +@@ -552,13 +514,9 @@ static void log_gpasswd_success (const c + "user %s removed by %s from group %s%s", + user, myname, group, suffix)); + #ifdef WITH_AUDIT +- snprintf (buf, 1023, +- "user %s removed by %s from group %s%s", +- user, myname, group, suffix); +- buf[1023] = '\0'; +- audit_logger (AUDIT_USER_ACCT, Prog, +- buf, +- group, AUDIT_NO_ID, ++ audit_logger_with_group (AUDIT_USER_MGMT, Prog, ++ "delete-user-from-group", ++ user, AUDIT_NO_ID, group, + SHADOW_AUDIT_SUCCESS); + #endif + } else if (rflg) { +@@ -566,13 +524,9 @@ static void log_gpasswd_success (const c + "password of group %s removed by %s%s", + group, myname, suffix)); + #ifdef WITH_AUDIT +- snprintf (buf, 1023, +- "password of group %s removed by %s%s", +- group, myname, suffix); +- buf[1023] = '\0'; +- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, +- buf, +- group, AUDIT_NO_ID, ++ audit_logger_with_group (AUDIT_GRP_CHAUTHTOK, Prog, ++ "delete-group-password", ++ myname, AUDIT_NO_ID, group, + SHADOW_AUDIT_SUCCESS); + #endif + } else if (Rflg) { +@@ -580,13 +534,9 @@ static void log_gpasswd_success (const c + "access to group %s restricted by %s%s", + group, myname, suffix)); + #ifdef WITH_AUDIT +- snprintf (buf, 1023, +- "access to group %s restricted by %s%s", +- group, myname, suffix); +- buf[1023] = '\0'; +- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, +- buf, +- group, AUDIT_NO_ID, ++ audit_logger_with_group (AUDIT_GRP_MGMT, Prog, ++ "restrict-group", ++ myname, AUDIT_NO_ID, group, + SHADOW_AUDIT_SUCCESS); + #endif + } else if (Aflg || Mflg) { +@@ -596,13 +546,9 @@ static void log_gpasswd_success (const c + "administrators of group %s set by %s to %s%s", + group, myname, admins, suffix)); + #ifdef WITH_AUDIT +- snprintf (buf, 1023, +- "administrators of group %s set by %s to %s%s", +- group, myname, admins, suffix); +- buf[1023] = '\0'; +- audit_logger (AUDIT_USER_ACCT, Prog, +- buf, +- group, AUDIT_NO_ID, ++ audit_logger_with_group (AUDIT_GRP_MGMT, Prog, ++ "set-admins-of-group", ++ admins, AUDIT_NO_ID, group, + SHADOW_AUDIT_SUCCESS); + #endif + } +@@ -612,13 +558,9 @@ static void log_gpasswd_success (const c + "members of group %s set by %s to %s%s", + group, myname, members, suffix)); + #ifdef WITH_AUDIT +- snprintf (buf, 1023, +- "members of group %s set by %s to %s%s", +- group, myname, members, suffix); +- buf[1023] = '\0'; +- audit_logger (AUDIT_USER_ACCT, Prog, +- buf, +- group, AUDIT_NO_ID, ++ audit_logger_with_group (AUDIT_USER_MGMT, Prog, ++ "add-users-to-group", ++ members, AUDIT_NO_ID, group, + SHADOW_AUDIT_SUCCESS); + #endif + } +@@ -627,13 +569,9 @@ static void log_gpasswd_success (const c + "password of group %s changed by %s%s", + group, myname, suffix)); + #ifdef WITH_AUDIT +- snprintf (buf, 1023, +- "password of group %s changed by %s%s", +- group, myname, suffix); +- buf[1023] = '\0'; +- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, +- buf, +- group, AUDIT_NO_ID, ++ audit_logger_with_group (AUDIT_GRP_CHAUTHTOK, Prog, ++ "change-password", ++ myname, AUDIT_NO_ID, group, + SHADOW_AUDIT_SUCCESS); + #endif + } +diff -up shadow-4.6/src/groupadd.c.audit-update shadow-4.6/src/groupadd.c +--- shadow-4.6/src/groupadd.c.audit-update 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/src/groupadd.c 2018-05-28 15:02:53.137910337 +0200 +@@ -130,6 +130,15 @@ static /*@noreturn@*/void usage (int sta + exit (status); + } + ++static void fail_exit(int status) ++{ ++#ifdef WITH_AUDIT ++ audit_logger(AUDIT_ADD_GROUP, Prog, "add-group", group_name, ++ AUDIT_NO_ID, SHADOW_AUDIT_FAILURE); ++#endif ++ exit (status); ++} ++ + /* + * new_grent - initialize the values in a group file entry + * +@@ -213,7 +222,7 @@ static void grp_update (void) + fprintf (stderr, + _("%s: failed to prepare the new %s entry '%s'\n"), + Prog, gr_dbname (), grp.gr_name); +- exit (E_GRP_UPDATE); ++ fail_exit (E_GRP_UPDATE); + } + #ifdef SHADOWGRP + /* +@@ -223,7 +232,7 @@ static void grp_update (void) + fprintf (stderr, + _("%s: failed to prepare the new %s entry '%s'\n"), + Prog, sgr_dbname (), sgrp.sg_name); +- exit (E_GRP_UPDATE); ++ fail_exit (E_GRP_UPDATE); + } + #endif /* SHADOWGRP */ + } +@@ -247,7 +256,7 @@ static void check_new_name (void) + fprintf (stderr, _("%s: '%s' is not a valid group name\n"), + Prog, group_name); + +- exit (E_BAD_ARG); ++ fail_exit (E_BAD_ARG); + } + + /* +@@ -263,11 +272,11 @@ static void close_files (void) + fprintf (stderr, + _("%s: failure while writing changes to %s\n"), + Prog, gr_dbname ()); +- exit (E_GRP_UPDATE); ++ fail_exit (E_GRP_UPDATE); + } + #ifdef WITH_AUDIT + audit_logger (AUDIT_ADD_GROUP, Prog, +- "adding group to /etc/group", ++ "add-group", + group_name, (unsigned int) group_id, + SHADOW_AUDIT_SUCCESS); + #endif +@@ -285,11 +294,11 @@ static void close_files (void) + fprintf (stderr, + _("%s: failure while writing changes to %s\n"), + Prog, sgr_dbname ()); +- exit (E_GRP_UPDATE); ++ fail_exit (E_GRP_UPDATE); + } + #ifdef WITH_AUDIT +- audit_logger (AUDIT_ADD_GROUP, Prog, +- "adding group to /etc/gshadow", ++ audit_logger (AUDIT_GRP_MGMT, Prog, ++ "add-shadow-group", + group_name, (unsigned int) group_id, + SHADOW_AUDIT_SUCCESS); + #endif +@@ -303,12 +312,6 @@ static void close_files (void) + #endif /* SHADOWGRP */ + + /* Report success at the system level */ +-#ifdef WITH_AUDIT +- audit_logger (AUDIT_ADD_GROUP, Prog, +- "", +- group_name, (unsigned int) group_id, +- SHADOW_AUDIT_SUCCESS); +-#endif + SYSLOG ((LOG_INFO, "new group: name=%s, GID=%u", + group_name, (unsigned int) group_id)); + del_cleanup (cleanup_report_add_group); +@@ -326,7 +329,7 @@ static void open_files (void) + fprintf (stderr, + _("%s: cannot lock %s; try again later.\n"), + Prog, gr_dbname ()); +- exit (E_GRP_UPDATE); ++ fail_exit (E_GRP_UPDATE); + } + add_cleanup (cleanup_unlock_group, NULL); + +@@ -336,7 +339,7 @@ static void open_files (void) + fprintf (stderr, + _("%s: cannot lock %s; try again later.\n"), + Prog, sgr_dbname ()); +- exit (E_GRP_UPDATE); ++ fail_exit (E_GRP_UPDATE); + } + add_cleanup (cleanup_unlock_gshadow, NULL); + } +@@ -352,7 +355,7 @@ static void open_files (void) + if (gr_open (O_CREAT | O_RDWR) == 0) { + fprintf (stderr, _("%s: cannot open %s\n"), Prog, gr_dbname ()); + SYSLOG ((LOG_WARN, "cannot open %s", gr_dbname ())); +- exit (E_GRP_UPDATE); ++ fail_exit (E_GRP_UPDATE); + } + + #ifdef SHADOWGRP +@@ -362,7 +365,7 @@ static void open_files (void) + _("%s: cannot open %s\n"), + Prog, sgr_dbname ()); + SYSLOG ((LOG_WARN, "cannot open %s", sgr_dbname ())); +- exit (E_GRP_UPDATE); ++ fail_exit (E_GRP_UPDATE); + } + } + #endif /* SHADOWGRP */ +@@ -495,7 +498,7 @@ static void check_flags (void) + fprintf (stderr, + _("%s: group '%s' already exists\n"), + Prog, group_name); +- exit (E_NAME_IN_USE); ++ fail_exit (E_NAME_IN_USE); + } + + if (gflg && (prefix_getgrgid (group_id) != NULL)) { +@@ -514,7 +517,7 @@ static void check_flags (void) + fprintf (stderr, + _("%s: GID '%lu' already exists\n"), + Prog, (unsigned long int) group_id); +- exit (E_GID_IN_USE); ++ fail_exit (E_GID_IN_USE); + } + } + } +@@ -542,7 +545,7 @@ static void check_perms (void) + fprintf (stderr, + _("%s: Cannot determine your user name.\n"), + Prog); +- exit (1); ++ fail_exit (1); + } + + retval = pam_start ("groupadd", pampw->pw_name, &conv, &pamh); +@@ -562,7 +565,7 @@ static void check_perms (void) + if (NULL != pamh) { + (void) pam_end (pamh, retval); + } +- exit (1); ++ fail_exit (1); + } + (void) pam_end (pamh, retval); + #endif /* USE_PAM */ +@@ -595,7 +598,7 @@ int main (int argc, char **argv) + fprintf (stderr, + _("%s: Cannot setup cleanup service.\n"), + Prog); +- exit (1); ++ fail_exit (1); + } + + /* +@@ -617,7 +620,7 @@ int main (int argc, char **argv) + + if (!gflg) { + if (find_new_gid (rflg, &group_id, NULL) < 0) { +- exit (E_GID_IN_USE); ++ fail_exit (E_GID_IN_USE); + } + } + +diff -up shadow-4.6/src/groupdel.c.audit-update shadow-4.6/src/groupdel.c +--- shadow-4.6/src/groupdel.c.audit-update 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/src/groupdel.c 2018-05-28 15:01:09.914717585 +0200 +@@ -105,6 +105,15 @@ static /*@noreturn@*/void usage (int sta + exit (status); + } + ++static void fail_exit(int status) ++{ ++#ifdef WITH_AUDIT ++ audit_logger(AUDIT_GRP_MGMT, Prog, "delete-group", group_name, ++ AUDIT_NO_ID, SHADOW_AUDIT_FAILURE); ++#endif ++ exit (status); ++} ++ + /* + * grp_update - update group file entries + * +@@ -131,7 +140,7 @@ static void grp_update (void) + fprintf (stderr, + _("%s: cannot remove entry '%s' from %s\n"), + Prog, group_name, gr_dbname ()); +- exit (E_GRP_UPDATE); ++ fail_exit (E_GRP_UPDATE); + } + + #ifdef SHADOWGRP +@@ -143,7 +152,7 @@ static void grp_update (void) + fprintf (stderr, + _("%s: cannot remove entry '%s' from %s\n"), + Prog, group_name, sgr_dbname ()); +- exit (E_GRP_UPDATE); ++ fail_exit (E_GRP_UPDATE); + } + } + #endif /* SHADOWGRP */ +@@ -162,12 +171,12 @@ static void close_files (void) + fprintf (stderr, + _("%s: failure while writing changes to %s\n"), + Prog, gr_dbname ()); +- exit (E_GRP_UPDATE); ++ fail_exit (E_GRP_UPDATE); + } + + #ifdef WITH_AUDIT + audit_logger (AUDIT_DEL_GROUP, Prog, +- "removing group from /etc/group", ++ "delete-group", + group_name, (unsigned int) group_id, + SHADOW_AUDIT_SUCCESS); + #endif +@@ -187,12 +196,12 @@ static void close_files (void) + fprintf (stderr, + _("%s: failure while writing changes to %s\n"), + Prog, sgr_dbname ()); +- exit (E_GRP_UPDATE); ++ fail_exit (E_GRP_UPDATE); + } + + #ifdef WITH_AUDIT +- audit_logger (AUDIT_DEL_GROUP, Prog, +- "removing group from /etc/gshadow", ++ audit_logger (AUDIT_GRP_MGMT, Prog, ++ "delete-shadow-group", + group_name, (unsigned int) group_id, + SHADOW_AUDIT_SUCCESS); + #endif +@@ -206,13 +215,6 @@ static void close_files (void) + } + #endif /* SHADOWGRP */ + +- /* Report success at the system level */ +-#ifdef WITH_AUDIT +- audit_logger (AUDIT_DEL_GROUP, Prog, +- "", +- group_name, (unsigned int) group_id, +- SHADOW_AUDIT_SUCCESS); +-#endif + SYSLOG ((LOG_INFO, "group '%s' removed\n", group_name)); + del_cleanup (cleanup_report_del_group); + } +@@ -229,7 +231,7 @@ static void open_files (void) + fprintf (stderr, + _("%s: cannot lock %s; try again later.\n"), + Prog, gr_dbname ()); +- exit (E_GRP_UPDATE); ++ fail_exit (E_GRP_UPDATE); + } + add_cleanup (cleanup_unlock_group, NULL); + #ifdef SHADOWGRP +@@ -238,7 +240,7 @@ static void open_files (void) + fprintf (stderr, + _("%s: cannot lock %s; try again later.\n"), + Prog, sgr_dbname ()); +- exit (E_GRP_UPDATE); ++ fail_exit (E_GRP_UPDATE); + } + add_cleanup (cleanup_unlock_gshadow, NULL); + } +@@ -256,7 +258,7 @@ static void open_files (void) + _("%s: cannot open %s\n"), + Prog, gr_dbname ()); + SYSLOG ((LOG_WARN, "cannot open %s", gr_dbname ())); +- exit (E_GRP_UPDATE); ++ fail_exit (E_GRP_UPDATE); + } + #ifdef SHADOWGRP + if (is_shadow_grp) { +@@ -265,7 +267,7 @@ static void open_files (void) + _("%s: cannot open %s\n"), + Prog, sgr_dbname ()); + SYSLOG ((LOG_WARN, "cannot open %s", sgr_dbname ())); +- exit (E_GRP_UPDATE); ++ fail_exit (E_GRP_UPDATE); + } + } + #endif /* SHADOWGRP */ +@@ -306,7 +308,7 @@ static void group_busy (gid_t gid) + fprintf (stderr, + _("%s: cannot remove the primary group of user '%s'\n"), + Prog, pwd->pw_name); +- exit (E_GROUP_BUSY); ++ fail_exit (E_GROUP_BUSY); + } + + /* +@@ -391,7 +393,7 @@ int main (int argc, char **argv) + fprintf (stderr, + _("%s: Cannot setup cleanup service.\n"), + Prog); +- exit (1); ++ fail_exit (1); + } + + process_flags (argc, argv); +@@ -405,7 +407,7 @@ int main (int argc, char **argv) + fprintf (stderr, + _("%s: Cannot determine your user name.\n"), + Prog); +- exit (1); ++ fail_exit (1); + } + + retval = pam_start ("groupdel", pampw->pw_name, &conv, &pamh); +@@ -426,7 +428,7 @@ int main (int argc, char **argv) + if (NULL != pamh) { + (void) pam_end (pamh, retval); + } +- exit (1); ++ fail_exit (1); + } + (void) pam_end (pamh, retval); + #endif /* USE_PAM */ +@@ -446,7 +448,7 @@ int main (int argc, char **argv) + fprintf (stderr, + _("%s: group '%s' does not exist\n"), + Prog, group_name); +- exit (E_NOTFOUND); ++ fail_exit (E_NOTFOUND); + } + + group_id = grp->gr_gid; +@@ -470,7 +472,7 @@ int main (int argc, char **argv) + _("%s: %s is the NIS master\n"), + Prog, nis_master); + } +- exit (E_NOTFOUND); ++ fail_exit (E_NOTFOUND); + } + #endif + +diff -up shadow-4.6/src/groupmod.c.audit-update shadow-4.6/src/groupmod.c +--- shadow-4.6/src/groupmod.c.audit-update 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/src/groupmod.c 2018-05-28 15:01:09.915717607 +0200 +@@ -449,7 +449,7 @@ static void close_files (void) + exit (E_GRP_UPDATE); + } + #ifdef WITH_AUDIT +- audit_logger (AUDIT_USER_ACCT, Prog, ++ audit_logger (AUDIT_GRP_MGMT, Prog, + info_group.audit_msg, + group_name, AUDIT_NO_ID, + SHADOW_AUDIT_SUCCESS); +@@ -472,7 +472,14 @@ static void close_files (void) + exit (E_GRP_UPDATE); + } + #ifdef WITH_AUDIT +- audit_logger (AUDIT_USER_ACCT, Prog, ++ /* If both happened, log password change as its more important */ ++ if (pflg) ++ audit_logger (AUDIT_GRP_CHAUTHTOK, Prog, ++ info_gshadow.audit_msg, ++ group_name, AUDIT_NO_ID, ++ SHADOW_AUDIT_SUCCESS); ++ else ++ audit_logger (AUDIT_GRP_MGMT, Prog, + info_gshadow.audit_msg, + group_name, AUDIT_NO_ID, + SHADOW_AUDIT_SUCCESS); +@@ -495,7 +502,7 @@ static void close_files (void) + exit (E_GRP_UPDATE); + } + #ifdef WITH_AUDIT +- audit_logger (AUDIT_USER_ACCT, Prog, ++ audit_logger (AUDIT_GRP_MGMT, Prog, + info_passwd.audit_msg, + group_name, AUDIT_NO_ID, + SHADOW_AUDIT_SUCCESS); +@@ -510,8 +517,8 @@ static void close_files (void) + } + + #ifdef WITH_AUDIT +- audit_logger (AUDIT_USER_ACCT, Prog, +- "modifying group", ++ audit_logger (AUDIT_GRP_MGMT, Prog, ++ "modify-group", + group_name, AUDIT_NO_ID, + SHADOW_AUDIT_SUCCESS); + #endif +@@ -523,6 +530,8 @@ static void close_files (void) + */ + static void prepare_failure_reports (void) + { ++ char *nv_pair, nv[64]; ++ + info_group.name = group_name; + #ifdef SHADOWGRP + info_gshadow.name = group_name; +@@ -535,76 +544,109 @@ static void prepare_failure_reports (voi + #endif + info_passwd.audit_msg = xmalloc (512); + +- (void) snprintf (info_group.audit_msg, 511, +- "changing %s; ", gr_dbname ()); ++ info_group.action = xmalloc (512); + #ifdef SHADOWGRP +- (void) snprintf (info_gshadow.audit_msg, 511, +- "changing %s; ", sgr_dbname ()); ++ info_gshadow.action = xmalloc (512); + #endif +- (void) snprintf (info_passwd.audit_msg, 511, +- "changing %s; ", pw_dbname ()); ++ info_passwd.action = xmalloc (512); + +- info_group.action = info_group.audit_msg +- + strlen (info_group.audit_msg); ++ (void) snprintf (info_group.audit_msg, 511, ++ "changing-group"); + #ifdef SHADOWGRP +- info_gshadow.action = info_gshadow.audit_msg +- + strlen (info_gshadow.audit_msg); ++ (void) snprintf (info_gshadow.audit_msg, 511, ++ "changing-shadow-group"); + #endif +- info_passwd.action = info_passwd.audit_msg +- + strlen (info_passwd.audit_msg); ++ (void) snprintf (info_passwd.audit_msg, 511, ++ "changing-group-passwd"); + ++ nv_pair = audit_encode_nv_string(" grp", group_name, ++ strlen(group_name)); ++ if(nv_pair) { ++ strncat(info_group.audit_msg, nv_pair, ++ 511 - strlen(info_group.audit_msg)); ++#ifdef SHADOWGRP ++ strncat(info_gshadow.audit_msg, nv_pair, ++ 511 - strlen(info_gshadow.audit_msg)); ++#endif ++ strncat(info_passwd.audit_msg, nv_pair, ++ 511 - strlen(info_passwd.audit_msg)); ++ free(nv_pair); ++ } ++ snprintf(nv, sizeof(nv), " gid=%lu", (unsigned long)group_id); ++ strncat(info_group.audit_msg, nv, 511 - strlen(info_group.audit_msg)); ++ strncat(info_passwd.audit_msg, nv, 511 - strlen(info_passwd.audit_msg)); ++ + (void) snprintf (info_group.action, +- 511 - strlen (info_group.audit_msg), ++ 511, + "group %s/%lu", + group_name, (unsigned long int) group_id); + #ifdef SHADOWGRP + (void) snprintf (info_gshadow.action, +- 511 - strlen (info_group.audit_msg), ++ 511, + "group %s", group_name); + #endif + (void) snprintf (info_passwd.action, +- 511 - strlen (info_group.audit_msg), ++ 511, + "group %s/%lu", + group_name, (unsigned long int) group_id); + + if (nflg) { ++ nv_pair = audit_encode_nv_string(" new_group", group_newname, ++ strlen(group_newname)); ++ strncat(info_group.audit_msg, nv_pair, ++ 511 - strlen(info_group.audit_msg)); + strncat (info_group.action, ", new name: ", +- 511 - strlen (info_group.audit_msg)); ++ 511 - strlen (info_group.action)); + strncat (info_group.action, group_newname, +- 511 - strlen (info_group.audit_msg)); ++ 511 - strlen (info_group.action)); + + #ifdef SHADOWGRP ++ strncat(info_gshadow.audit_msg, nv_pair, ++ 511 - strlen(info_gshadow.audit_msg)); + strncat (info_gshadow.action, ", new name: ", +- 511 - strlen (info_gshadow.audit_msg)); ++ 511 - strlen (info_gshadow.action)); + strncat (info_gshadow.action, group_newname, +- 511 - strlen (info_gshadow.audit_msg)); ++ 511 - strlen (info_gshadow.action)); + #endif + ++ strncat(info_passwd.audit_msg, nv_pair, ++ 511 - strlen(info_passwd.audit_msg)); + strncat (info_passwd.action, ", new name: ", +- 511 - strlen (info_passwd.audit_msg)); ++ 511 - strlen (info_passwd.action)); + strncat (info_passwd.action, group_newname, +- 511 - strlen (info_passwd.audit_msg)); ++ 511 - strlen (info_passwd.action)); ++ free(nv_pair); + } + if (pflg) { ++ strncat(info_passwd.audit_msg, "op=change-password", ++ 511 - strlen (info_passwd.action)); ++ ++ /* Note: audit doesn't want this value recorded */ + strncat (info_group.action, ", new password", +- 511 - strlen (info_group.audit_msg)); ++ 511 - strlen (info_group.action)); + + #ifdef SHADOWGRP + strncat (info_gshadow.action, ", new password", +- 511 - strlen (info_gshadow.audit_msg)); ++ 511 - strlen (info_gshadow.action)); + #endif + } + if (gflg) { ++ snprintf(nv, sizeof(nv), " new_gid=%lu", (unsigned long)group_newid); ++ strncat(info_group.audit_msg, nv, ++ 511 - strlen(info_group.audit_msg)); ++ strncat(info_passwd.audit_msg, nv, ++ 511 - strlen(info_passwd.audit_msg)); ++ + strncat (info_group.action, ", new gid: ", +- 511 - strlen (info_group.audit_msg)); ++ 511 - strlen (info_group.action)); + (void) snprintf (info_group.action+strlen (info_group.action), +- 511 - strlen (info_group.audit_msg), ++ 511 - strlen (info_group.action), + "%lu", (unsigned long int) group_newid); + + strncat (info_passwd.action, ", new gid: ", +- 511 - strlen (info_passwd.audit_msg)); ++ 511 - strlen (info_passwd.action)); + (void) snprintf (info_passwd.action+strlen (info_passwd.action), +- 511 - strlen (info_passwd.audit_msg), ++ 511 - strlen (info_passwd.action), + "%lu", (unsigned long int) group_newid); + } + info_group.audit_msg[511] = '\0'; +@@ -612,6 +654,11 @@ static void prepare_failure_reports (voi + info_gshadow.audit_msg[511] = '\0'; + #endif + info_passwd.audit_msg[511] = '\0'; ++ info_group.action[511] = '\0'; ++#ifdef SHADOWGRP ++ info_gshadow.action[511] = '\0'; ++#endif ++ info_passwd.action[511] = '\0'; + + // FIXME: add a system cleanup + add_cleanup (cleanup_report_mod_group, &info_group); +diff -up shadow-4.6/src/chage.c.audit-update shadow-4.6/src/chage.c +--- shadow-4.6/src/chage.c.audit-update 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/src/chage.c 2018-05-28 15:01:09.915717607 +0200 +@@ -126,9 +126,10 @@ static /*@noreturn@*/void fail_exit (int + + #ifdef WITH_AUDIT + if (E_SUCCESS != code) { +- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, +- "change age", +- user_name, (unsigned int) user_uid, 0); ++ audit_logger (AUDIT_USER_MGMT, Prog, ++ "change-age", ++ user_name, (unsigned int) user_uid, ++ SHADOW_AUDIT_FAILURE); + } + #endif + +@@ -873,11 +874,7 @@ int main (int argc, char **argv) + fprintf (stderr, _("%s: Permission denied.\n"), Prog); + fail_exit (E_NOPERM); + } +-#ifdef WITH_AUDIT +- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, +- "display aging info", +- user_name, (unsigned int) user_uid, 1); +-#endif ++ /* Displaying fields is not of interest to audit */ + list_fields (); + fail_exit (E_SUCCESS); + } +@@ -896,41 +893,43 @@ int main (int argc, char **argv) + } + #ifdef WITH_AUDIT + else { +- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, +- "change all aging information", +- user_name, (unsigned int) user_uid, 1); ++ audit_logger (AUDIT_USER_MGMT, Prog, ++ "change-all-aging-information", ++ user_name, (unsigned int) user_uid, ++ SHADOW_AUDIT_SUCCESS); + } + #endif + } else { + #ifdef WITH_AUDIT + if (Mflg) { +- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, +- "change max age", +- user_name, (unsigned int) user_uid, 1); ++ audit_logger (AUDIT_USER_MGMT, Prog, ++ "change-max-age", ++ user_name, (unsigned int) user_uid, ++ SHADOW_AUDIT_SUCCESS); + } + if (mflg) { +- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, +- "change min age", ++ audit_logger (AUDIT_USER_MGMT, Prog, ++ "change-min-age", + user_name, (unsigned int) user_uid, 1); + } + if (dflg) { +- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, +- "change last change date", ++ audit_logger (AUDIT_USER_MGMT, Prog, ++ "change-last-change-date", + user_name, (unsigned int) user_uid, 1); + } + if (Wflg) { +- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, +- "change passwd warning", ++ audit_logger (AUDIT_USER_MGMT, Prog, ++ "change-passwd-warning", + user_name, (unsigned int) user_uid, 1); + } + if (Iflg) { +- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, +- "change inactive days", ++ audit_logger (AUDIT_USER_MGMT, Prog, ++ "change-inactive-days", + user_name, (unsigned int) user_uid, 1); + } + if (Eflg) { +- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, +- "change passwd expiration", ++ audit_logger (AUDIT_USER_MGMT, Prog, ++ "change-passwd-expiration", + user_name, (unsigned int) user_uid, 1); + } + #endif +diff -up shadow-4.6/src/newgrp.c.audit-update shadow-4.6/src/newgrp.c +--- shadow-4.6/src/newgrp.c.audit-update 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/src/newgrp.c 2018-05-28 15:01:09.915717607 +0200 +@@ -206,11 +206,12 @@ static void check_perms (const struct gr + strcmp (cpasswd, grp->gr_passwd) != 0) { + #ifdef WITH_AUDIT + snprintf (audit_buf, sizeof(audit_buf), +- "authentication new-gid=%lu", ++ "authentication new_gid=%lu", + (unsigned long) grp->gr_gid); + audit_logger (AUDIT_GRP_AUTH, Prog, + audit_buf, NULL, +- (unsigned int) getuid (), 0); ++ (unsigned int) getuid (), ++ SHADOW_AUDIT_FAILURE); + #endif + SYSLOG ((LOG_INFO, + "Invalid password for group '%s' from '%s'", +@@ -221,11 +222,12 @@ static void check_perms (const struct gr + } + #ifdef WITH_AUDIT + snprintf (audit_buf, sizeof(audit_buf), +- "authentication new-gid=%lu", ++ "authentication new_gid=%lu", + (unsigned long) grp->gr_gid); + audit_logger (AUDIT_GRP_AUTH, Prog, + audit_buf, NULL, +- (unsigned int) getuid (), 1); ++ (unsigned int) getuid (), ++ SHADOW_AUDIT_SUCCESS); + #endif + } + +@@ -236,19 +238,6 @@ failure: + * harm. -- JWP + */ + closelog (); +-#ifdef WITH_AUDIT +- if (groupname) { +- snprintf (audit_buf, sizeof(audit_buf), +- "changing new-group=%s", groupname); +- audit_logger (AUDIT_CHGRP_ID, Prog, +- audit_buf, NULL, +- (unsigned int) getuid (), 0); +- } else { +- audit_logger (AUDIT_CHGRP_ID, Prog, +- "changing", NULL, +- (unsigned int) getuid (), 0); +- } +-#endif + exit (EXIT_FAILURE); + } + +@@ -320,15 +309,27 @@ static void syslog_sg (const char *name, + is_newgrp ? "newgrp" : "sg", strerror (errno)); + #ifdef WITH_AUDIT + if (group) { +- snprintf (audit_buf, sizeof(audit_buf), +- "changing new-group=%s", group); ++ char enc_group[(GROUP_NAME_MAX_LENGTH*2)+1]; ++ int len = strnlen(group, sizeof(enc_group)/2); ++ if (audit_value_needs_encoding(group, len)) { ++ snprintf (audit_buf, sizeof(audit_buf), ++ "changing new_group=%s", ++ audit_encode_value(enc_group, ++ group, len)); ++ } else { ++ snprintf (audit_buf, sizeof(audit_buf), ++ "changing new_group=\"%s\"", ++ group); ++ } + audit_logger (AUDIT_CHGRP_ID, Prog, + audit_buf, NULL, +- (unsigned int) getuid (), 0); ++ (unsigned int) getuid (), ++ SHADOW_AUDIT_FAILURE); + } else { + audit_logger (AUDIT_CHGRP_ID, Prog, + "changing", NULL, +- (unsigned int) getuid (), 0); ++ (unsigned int) getuid (), ++ SHADOW_AUDIT_FAILURE); + } + #endif + exit (EXIT_FAILURE); +@@ -457,7 +458,7 @@ int main (int argc, char **argv) + #ifdef WITH_AUDIT + audit_logger (AUDIT_CHGRP_ID, Prog, + "changing", NULL, +- (unsigned int) getuid (), 0); ++ (unsigned int) getuid (), SHADOW_AUDIT_FAILURE); + #endif + SYSLOG ((LOG_WARN, "Cannot determine the user name of the caller (UID %lu)", + (unsigned long) getuid ())); +@@ -573,15 +574,26 @@ int main (int argc, char **argv) + perror ("getgroups"); + #ifdef WITH_AUDIT + if (group) { +- snprintf (audit_buf, sizeof(audit_buf), +- "changing new-group=%s", group); ++ char enc_group[(GROUP_NAME_MAX_LENGTH*2)+1]; ++ int len = strnlen(group, sizeof(enc_group)/2); ++ if (audit_value_needs_encoding(group, len)) { ++ snprintf (audit_buf, sizeof(audit_buf), ++ "changing new_group=%s", ++ audit_encode_value(enc_group, ++ group, len)); ++ } else { ++ snprintf (audit_buf, sizeof(audit_buf), ++ "changing new_group=\"%s\"", group); ++ } + audit_logger (AUDIT_CHGRP_ID, Prog, + audit_buf, NULL, +- (unsigned int) getuid (), 0); ++ (unsigned int) getuid (), ++ SHADOW_AUDIT_FAILURE); + } else { + audit_logger (AUDIT_CHGRP_ID, Prog, + "changing", NULL, +- (unsigned int) getuid (), 0); ++ (unsigned int) getuid (), ++ SHADOW_AUDIT_FAILURE); + } + #endif + exit (EXIT_FAILURE); +@@ -738,10 +750,10 @@ int main (int argc, char **argv) + perror ("setgid"); + #ifdef WITH_AUDIT + snprintf (audit_buf, sizeof(audit_buf), +- "changing new-gid=%lu", (unsigned long) gid); ++ "changing new_gid=%lu", (unsigned long) gid); + audit_logger (AUDIT_CHGRP_ID, Prog, + audit_buf, NULL, +- (unsigned int) getuid (), 0); ++ (unsigned int) getuid (), SHADOW_AUDIT_FAILURE); + #endif + exit (EXIT_FAILURE); + } +@@ -750,10 +762,10 @@ int main (int argc, char **argv) + perror ("setuid"); + #ifdef WITH_AUDIT + snprintf (audit_buf, sizeof(audit_buf), +- "changing new-gid=%lu", (unsigned long) gid); ++ "changing new_gid=%lu", (unsigned long) gid); + audit_logger (AUDIT_CHGRP_ID, Prog, + audit_buf, NULL, +- (unsigned int) getuid (), 0); ++ (unsigned int) getuid (), SHADOW_AUDIT_FAILURE); + #endif + exit (EXIT_FAILURE); + } +@@ -767,10 +779,10 @@ int main (int argc, char **argv) + execl (SHELL, "sh", "-c", command, (char *) 0); + #ifdef WITH_AUDIT + snprintf (audit_buf, sizeof(audit_buf), +- "changing new-gid=%lu", (unsigned long) gid); ++ "changing new_gid=%lu", (unsigned long) gid); + audit_logger (AUDIT_CHGRP_ID, Prog, + audit_buf, NULL, +- (unsigned int) getuid (), 0); ++ (unsigned int) getuid (), SHADOW_AUDIT_FAILURE); + #endif + perror (SHELL); + exit ((errno == ENOENT) ? E_CMD_NOTFOUND : E_CMD_NOEXEC); +@@ -834,11 +846,11 @@ int main (int argc, char **argv) + } + + #ifdef WITH_AUDIT +- snprintf (audit_buf, sizeof(audit_buf), "changing new-gid=%lu", ++ snprintf (audit_buf, sizeof(audit_buf), "changing new_gid=%lu", + (unsigned long) gid); + audit_logger (AUDIT_CHGRP_ID, Prog, + audit_buf, NULL, +- (unsigned int) getuid (), 1); ++ (unsigned int) getuid (), SHADOW_AUDIT_SUCCESS); + #endif + /* + * Exec the login shell and go away. We are trying to get back to +@@ -862,15 +874,24 @@ int main (int argc, char **argv) + closelog (); + #ifdef WITH_AUDIT + if (NULL != group) { +- snprintf (audit_buf, sizeof(audit_buf), +- "changing new-group=%s", group); ++ char enc_group[(GROUP_NAME_MAX_LENGTH*2)+1]; ++ int len = strnlen(group, sizeof(enc_group)/2); ++ if (audit_value_needs_encoding(group, len)) { ++ snprintf (audit_buf, sizeof(audit_buf), ++ "changing new_group=%s", ++ audit_encode_value(enc_group, ++ group, len)); ++ } else { ++ snprintf (audit_buf, sizeof(audit_buf), ++ "changing new_group=\"%s\"", group); ++ } + audit_logger (AUDIT_CHGRP_ID, Prog, + audit_buf, NULL, +- (unsigned int) getuid (), 0); ++ (unsigned int) getuid (), SHADOW_AUDIT_FAILURE); + } else { + audit_logger (AUDIT_CHGRP_ID, Prog, + "changing", NULL, +- (unsigned int) getuid (), 0); ++ (unsigned int) getuid (), SHADOW_AUDIT_FAILURE); + } + #endif + exit (EXIT_FAILURE); +diff -up shadow-4.6/src/useradd.c.audit-update shadow-4.6/src/useradd.c +--- shadow-4.6/src/useradd.c.audit-update 2018-05-28 15:01:09.903717352 +0200 ++++ shadow-4.6/src/useradd.c 2018-05-28 15:06:36.824662074 +0200 +@@ -229,6 +229,8 @@ static void create_mail (void); + */ + static void fail_exit (int code) + { ++ int type; ++ + if (home_added) { + if (rmdir (prefix_user_home) != 0) { + fprintf (stderr, +@@ -242,12 +244,6 @@ static void fail_exit (int code) + if (spw_unlock () == 0) { + fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, spw_dbname ()); + SYSLOG ((LOG_ERR, "failed to unlock %s", spw_dbname ())); +-#ifdef WITH_AUDIT +- audit_logger (AUDIT_ADD_USER, Prog, +- "unlocking shadow file", +- user_name, AUDIT_NO_ID, +- SHADOW_AUDIT_FAILURE); +-#endif + /* continue */ + } + } +@@ -255,12 +251,6 @@ static void fail_exit (int code) + if (pw_unlock () == 0) { + fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, pw_dbname ()); + SYSLOG ((LOG_ERR, "failed to unlock %s", pw_dbname ())); +-#ifdef WITH_AUDIT +- audit_logger (AUDIT_ADD_USER, Prog, +- "unlocking passwd file", +- user_name, AUDIT_NO_ID, +- SHADOW_AUDIT_FAILURE); +-#endif + /* continue */ + } + } +@@ -268,12 +258,6 @@ static void fail_exit (int code) + if (gr_unlock () == 0) { + fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, gr_dbname ()); + SYSLOG ((LOG_ERR, "failed to unlock %s", gr_dbname ())); +-#ifdef WITH_AUDIT +- audit_logger (AUDIT_ADD_USER, Prog, +- "unlocking group file", +- user_name, AUDIT_NO_ID, +- SHADOW_AUDIT_FAILURE); +-#endif + /* continue */ + } + } +@@ -282,12 +266,6 @@ static void fail_exit (int code) + if (sgr_unlock () == 0) { + fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sgr_dbname ()); + SYSLOG ((LOG_ERR, "failed to unlock %s", sgr_dbname ())); +-#ifdef WITH_AUDIT +- audit_logger (AUDIT_ADD_USER, Prog, +- "unlocking gshadow file", +- user_name, AUDIT_NO_ID, +- SHADOW_AUDIT_FAILURE); +-#endif + /* continue */ + } + } +@@ -297,12 +275,6 @@ static void fail_exit (int code) + if (sub_uid_unlock () == 0) { + fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sub_uid_dbname ()); + SYSLOG ((LOG_ERR, "failed to unlock %s", sub_uid_dbname ())); +-#ifdef WITH_AUDIT +- audit_logger (AUDIT_ADD_USER, Prog, +- "unlocking subordinate user file", +- user_name, AUDIT_NO_ID, +- SHADOW_AUDIT_FAILURE); +-#endif + /* continue */ + } + } +@@ -310,20 +282,19 @@ static void fail_exit (int code) + if (sub_gid_unlock () == 0) { + fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sub_gid_dbname ()); + SYSLOG ((LOG_ERR, "failed to unlock %s", sub_gid_dbname ())); +-#ifdef WITH_AUDIT +- audit_logger (AUDIT_ADD_USER, Prog, +- "unlocking subordinate group file", +- user_name, AUDIT_NO_ID, +- SHADOW_AUDIT_FAILURE); +-#endif + /* continue */ + } + } + #endif /* ENABLE_SUBIDS */ + + #ifdef WITH_AUDIT +- audit_logger (AUDIT_ADD_USER, Prog, +- "adding user", ++ if (code == E_PW_UPDATE || code >= E_GRP_UPDATE) ++ type = AUDIT_USER_MGMT; ++ else ++ type = AUDIT_ADD_USER; ++ ++ audit_logger (type, Prog, ++ "add-user", + user_name, AUDIT_NO_ID, + SHADOW_AUDIT_FAILURE); + #endif +@@ -673,7 +644,7 @@ static int set_defaults (void) + } + #ifdef WITH_AUDIT + audit_logger (AUDIT_USYS_CONFIG, Prog, +- "changing useradd defaults", ++ "changing-useradd-defaults", + NULL, AUDIT_NO_ID, + SHADOW_AUDIT_SUCCESS); + #endif +@@ -950,12 +921,6 @@ static void grp_update (void) + _("%s: Out of memory. Cannot update %s.\n"), + Prog, gr_dbname ()); + SYSLOG ((LOG_ERR, "failed to prepare the new %s entry '%s'", gr_dbname (), user_name)); +-#ifdef WITH_AUDIT +- audit_logger (AUDIT_ADD_USER, Prog, +- "adding user to group", +- user_name, AUDIT_NO_ID, +- SHADOW_AUDIT_FAILURE); +-#endif + fail_exit (E_GRP_UPDATE); /* XXX */ + } + +@@ -969,18 +934,12 @@ static void grp_update (void) + _("%s: failed to prepare the new %s entry '%s'\n"), + Prog, gr_dbname (), ngrp->gr_name); + SYSLOG ((LOG_ERR, "failed to prepare the new %s entry '%s'", gr_dbname (), user_name)); +-#ifdef WITH_AUDIT +- audit_logger (AUDIT_ADD_USER, Prog, +- "adding user to group", +- user_name, AUDIT_NO_ID, +- SHADOW_AUDIT_FAILURE); +-#endif + fail_exit (E_GRP_UPDATE); + } + #ifdef WITH_AUDIT +- audit_logger (AUDIT_ADD_USER, Prog, +- "adding user to group", +- user_name, AUDIT_NO_ID, ++ audit_logger_with_group (AUDIT_USER_MGMT, Prog, ++ "add-user-to-group", ++ user_name, AUDIT_NO_ID, ngrp->gr_name, + SHADOW_AUDIT_SUCCESS); + #endif + SYSLOG ((LOG_INFO, +@@ -1025,12 +984,6 @@ static void grp_update (void) + _("%s: Out of memory. Cannot update %s.\n"), + Prog, sgr_dbname ()); + SYSLOG ((LOG_ERR, "failed to prepare the new %s entry '%s'", sgr_dbname (), user_name)); +-#ifdef WITH_AUDIT +- audit_logger (AUDIT_ADD_USER, Prog, +- "adding user to shadow group", +- user_name, AUDIT_NO_ID, +- SHADOW_AUDIT_FAILURE); +-#endif + fail_exit (E_GRP_UPDATE); /* XXX */ + } + +@@ -1044,18 +997,13 @@ static void grp_update (void) + _("%s: failed to prepare the new %s entry '%s'\n"), + Prog, sgr_dbname (), nsgrp->sg_name); + SYSLOG ((LOG_ERR, "failed to prepare the new %s entry '%s'", sgr_dbname (), user_name)); +-#ifdef WITH_AUDIT +- audit_logger (AUDIT_ADD_USER, Prog, +- "adding user to shadow group", +- user_name, AUDIT_NO_ID, +- SHADOW_AUDIT_FAILURE); +-#endif ++ + fail_exit (E_GRP_UPDATE); + } + #ifdef WITH_AUDIT +- audit_logger (AUDIT_ADD_USER, Prog, +- "adding user to shadow group", +- user_name, AUDIT_NO_ID, ++ audit_logger_with_group (AUDIT_USER_MGMT, Prog, ++ "add-to-shadow-group", ++ user_name, AUDIT_NO_ID, nsgrp->sg_name, + SHADOW_AUDIT_SUCCESS); + #endif + SYSLOG ((LOG_INFO, +@@ -1407,7 +1355,7 @@ static void process_flags (int argc, cha + Prog, user_name); + #ifdef WITH_AUDIT + audit_logger (AUDIT_ADD_USER, Prog, +- "adding user", ++ "add-user", + user_name, AUDIT_NO_ID, + SHADOW_AUDIT_FAILURE); + #endif +@@ -1522,7 +1470,7 @@ static void close_files (void) + SYSLOG ((LOG_ERR, "failed to unlock %s", spw_dbname ())); + #ifdef WITH_AUDIT + audit_logger (AUDIT_ADD_USER, Prog, +- "unlocking shadow file", ++ "unlocking-shadow-file", + user_name, AUDIT_NO_ID, + SHADOW_AUDIT_FAILURE); + #endif +@@ -1535,7 +1483,7 @@ static void close_files (void) + SYSLOG ((LOG_ERR, "failed to unlock %s", pw_dbname ())); + #ifdef WITH_AUDIT + audit_logger (AUDIT_ADD_USER, Prog, +- "unlocking passwd file", ++ "unlocking-passwd-file", + user_name, AUDIT_NO_ID, + SHADOW_AUDIT_FAILURE); + #endif +@@ -1547,7 +1495,7 @@ static void close_files (void) + SYSLOG ((LOG_ERR, "failed to unlock %s", gr_dbname ())); + #ifdef WITH_AUDIT + audit_logger (AUDIT_ADD_USER, Prog, +- "unlocking group file", ++ "unlocking-group-file", + user_name, AUDIT_NO_ID, + SHADOW_AUDIT_FAILURE); + #endif +@@ -1561,7 +1509,7 @@ static void close_files (void) + SYSLOG ((LOG_ERR, "failed to unlock %s", sgr_dbname ())); + #ifdef WITH_AUDIT + audit_logger (AUDIT_ADD_USER, Prog, +- "unlocking gshadow file", ++ "unlocking-gshadow-file", + user_name, AUDIT_NO_ID, + SHADOW_AUDIT_FAILURE); + #endif +@@ -1577,7 +1525,7 @@ static void close_files (void) + SYSLOG ((LOG_ERR, "failed to unlock %s", sub_uid_dbname ())); + #ifdef WITH_AUDIT + audit_logger (AUDIT_ADD_USER, Prog, +- "unlocking subordinate user file", ++ "unlocking-subordinate-user-file", + user_name, AUDIT_NO_ID, + SHADOW_AUDIT_FAILURE); + #endif +@@ -1591,7 +1539,7 @@ static void close_files (void) + SYSLOG ((LOG_ERR, "failed to unlock %s", sub_gid_dbname ())); + #ifdef WITH_AUDIT + audit_logger (AUDIT_ADD_USER, Prog, +- "unlocking subordinate group file", ++ "unlocking-subordinate-group-file", + user_name, AUDIT_NO_ID, + SHADOW_AUDIT_FAILURE); + #endif +@@ -1783,7 +1731,7 @@ static void grp_add (void) + Prog, gr_dbname (), grp.gr_name); + #ifdef WITH_AUDIT + audit_logger (AUDIT_ADD_GROUP, Prog, +- "adding group", ++ "add-group", + grp.gr_name, AUDIT_NO_ID, + SHADOW_AUDIT_FAILURE); + #endif +@@ -1799,7 +1747,7 @@ static void grp_add (void) + Prog, sgr_dbname (), sgrp.sg_name); + #ifdef WITH_AUDIT + audit_logger (AUDIT_ADD_GROUP, Prog, +- "adding group", ++ "add-group", + grp.gr_name, AUDIT_NO_ID, + SHADOW_AUDIT_FAILURE); + #endif +@@ -1809,7 +1757,7 @@ static void grp_add (void) + SYSLOG ((LOG_INFO, "new group: name=%s, GID=%u", user_name, user_gid)); + #ifdef WITH_AUDIT + audit_logger (AUDIT_ADD_GROUP, Prog, +- "adding group", ++ "add-group", + grp.gr_name, AUDIT_NO_ID, + SHADOW_AUDIT_SUCCESS); + #endif +@@ -1970,12 +1918,6 @@ static void usr_update (void) + fprintf (stderr, + _("%s: failed to prepare the new %s entry '%s'\n"), + Prog, spw_dbname (), spent.sp_namp); +-#ifdef WITH_AUDIT +- audit_logger (AUDIT_ADD_USER, Prog, +- "adding shadow password", +- user_name, (unsigned int) user_id, +- SHADOW_AUDIT_FAILURE); +-#endif + fail_exit (E_PW_UPDATE); + } + #ifdef ENABLE_SUBIDS +@@ -1996,9 +1938,14 @@ static void usr_update (void) + #endif /* ENABLE_SUBIDS */ + + #ifdef WITH_AUDIT ++ /* ++ * Even though we have the ID of the user, we won't send it now ++ * because its not written to disk yet. After close_files it is ++ * and we can use the real ID thereafter. ++ */ + audit_logger (AUDIT_ADD_USER, Prog, +- "adding user", +- user_name, (unsigned int) user_id, ++ "add-user", ++ user_name, AUDIT_NO_ID, + SHADOW_AUDIT_SUCCESS); + #endif + /* +@@ -2032,12 +1979,6 @@ static void create_home (void) + fprintf (stderr, + _("%s: cannot create directory %s\n"), + Prog, prefix_user_home); +-#ifdef WITH_AUDIT +- audit_logger (AUDIT_ADD_USER, Prog, +- "adding home directory", +- user_name, (unsigned int) user_id, +- SHADOW_AUDIT_FAILURE); +-#endif + fail_exit (E_HOMEDIR); + } + (void) chown (prefix_user_home, user_id, user_gid); +@@ -2045,8 +1986,8 @@ static void create_home (void) + 0777 & ~getdef_num ("UMASK", GETDEF_DEFAULT_UMASK)); + home_added = true; + #ifdef WITH_AUDIT +- audit_logger (AUDIT_ADD_USER, Prog, +- "adding home directory", ++ audit_logger (AUDIT_USER_MGMT, Prog, ++ "add-home-dir", + user_name, (unsigned int) user_id, + SHADOW_AUDIT_SUCCESS); + #endif +@@ -2231,12 +2172,6 @@ int main (int argc, char **argv) + */ + if (prefix_getpwnam (user_name) != NULL) { /* local, no need for xgetpwnam */ + fprintf (stderr, _("%s: user '%s' already exists\n"), Prog, user_name); +-#ifdef WITH_AUDIT +- audit_logger (AUDIT_ADD_USER, Prog, +- "adding user", +- user_name, AUDIT_NO_ID, +- SHADOW_AUDIT_FAILURE); +-#endif + fail_exit (E_NAME_IN_USE); + } + +@@ -2252,12 +2187,6 @@ int main (int argc, char **argv) + fprintf (stderr, + _("%s: group %s exists - if you want to add this user to that group, use -g.\n"), + Prog, user_name); +-#ifdef WITH_AUDIT +- audit_logger (AUDIT_ADD_USER, Prog, +- "adding group", +- user_name, AUDIT_NO_ID, +- SHADOW_AUDIT_FAILURE); +-#endif + fail_exit (E_NAME_IN_USE); + } + } +@@ -2287,12 +2216,6 @@ int main (int argc, char **argv) + fprintf (stderr, + _("%s: UID %lu is not unique\n"), + Prog, (unsigned long) user_id); +-#ifdef WITH_AUDIT +- audit_logger (AUDIT_ADD_USER, Prog, +- "adding user", +- user_name, (unsigned int) user_id, +- SHADOW_AUDIT_FAILURE); +-#endif + fail_exit (E_UID_IN_USE); + } + } +@@ -2365,9 +2283,10 @@ int main (int argc, char **argv) + _("%s: warning: the user name %s to %s SELinux user mapping failed.\n"), + Prog, user_name, user_selinux); + #ifdef WITH_AUDIT +- audit_logger (AUDIT_ADD_USER, Prog, +- "adding SELinux user mapping", +- user_name, (unsigned int) user_id, 0); ++ audit_logger (AUDIT_ROLE_ASSIGN, Prog, ++ "add-selinux-user-mapping", ++ user_name, (unsigned int) user_id, ++ SHADOW_AUDIT_FAILURE); + #endif /* WITH_AUDIT */ + rv = E_SE_UPDATE; + } +diff -up shadow-4.6/src/userdel.c.audit-update shadow-4.6/src/userdel.c +--- shadow-4.6/src/userdel.c.audit-update 2018-05-28 15:01:09.909717479 +0200 ++++ shadow-4.6/src/userdel.c 2018-05-28 15:01:09.916717628 +0200 +@@ -219,9 +219,9 @@ static void update_groups (void) + * Update the DBM group file with the new entry as well. + */ + #ifdef WITH_AUDIT +- audit_logger (AUDIT_DEL_USER, Prog, +- "deleting user from group", +- user_name, (unsigned int) user_id, ++ audit_logger_with_group (AUDIT_USER_MGMT, Prog, ++ "deleting-user-from-group", ++ user_name, (unsigned int) user_id, ngrp->gr_name, + SHADOW_AUDIT_SUCCESS); + #endif /* WITH_AUDIT */ + SYSLOG ((LOG_INFO, "delete '%s' from group '%s'\n", +@@ -281,9 +281,9 @@ static void update_groups (void) + exit (E_GRP_UPDATE); + } + #ifdef WITH_AUDIT +- audit_logger (AUDIT_DEL_USER, Prog, +- "deleting user from shadow group", +- user_name, (unsigned int) user_id, ++ audit_logger_with_group (AUDIT_USER_MGMT, Prog, ++ "deleting-user-from-shadow-group", ++ user_name, (unsigned int) user_id, nsgrp->sg_name, + SHADOW_AUDIT_SUCCESS); + #endif /* WITH_AUDIT */ + SYSLOG ((LOG_INFO, "delete '%s' from shadow group '%s'\n", +@@ -360,9 +360,9 @@ static void remove_usergroup (void) + } + + #ifdef WITH_AUDIT +- audit_logger (AUDIT_DEL_GROUP, Prog, +- "deleting group", +- user_name, AUDIT_NO_ID, ++ audit_logger_with_group (AUDIT_DEL_GROUP, Prog, ++ "delete-group", ++ user_name, AUDIT_NO_ID, user_name, + SHADOW_AUDIT_SUCCESS); + #endif /* WITH_AUDIT */ + SYSLOG ((LOG_INFO, +@@ -378,9 +378,9 @@ static void remove_usergroup (void) + fail_exit (E_GRP_UPDATE); + } + #ifdef WITH_AUDIT +- audit_logger (AUDIT_DEL_GROUP, Prog, +- "deleting shadow group", +- user_name, AUDIT_NO_ID, ++ audit_logger_with_group (AUDIT_GRP_MGMT, Prog, ++ "delete-shadow-group", ++ user_name, AUDIT_NO_ID, user_name, + SHADOW_AUDIT_SUCCESS); + #endif /* WITH_AUDIT */ + SYSLOG ((LOG_INFO, +@@ -542,7 +542,7 @@ static void fail_exit (int code) + + #ifdef WITH_AUDIT + audit_logger (AUDIT_DEL_USER, Prog, +- "deleting user", ++ "delete-user", + user_name, (unsigned int) user_id, + SHADOW_AUDIT_FAILURE); + #endif /* WITH_AUDIT */ +@@ -562,24 +562,12 @@ static void open_files (void) + fprintf (stderr, + _("%s: cannot lock %s; try again later.\n"), + Prog, pw_dbname ()); +-#ifdef WITH_AUDIT +- audit_logger (AUDIT_DEL_USER, Prog, +- "locking password file", +- user_name, (unsigned int) user_id, +- SHADOW_AUDIT_FAILURE); +-#endif /* WITH_AUDIT */ + fail_exit (E_PW_UPDATE); + } + pw_locked = true; + if (pw_open (O_CREAT | O_RDWR) == 0) { + fprintf (stderr, + _("%s: cannot open %s\n"), Prog, pw_dbname ()); +-#ifdef WITH_AUDIT +- audit_logger (AUDIT_DEL_USER, Prog, +- "opening password file", +- user_name, (unsigned int) user_id, +- SHADOW_AUDIT_FAILURE); +-#endif /* WITH_AUDIT */ + fail_exit (E_PW_UPDATE); + } + if (is_shadow_pwd) { +@@ -587,12 +575,6 @@ static void open_files (void) + fprintf (stderr, + _("%s: cannot lock %s; try again later.\n"), + Prog, spw_dbname ()); +-#ifdef WITH_AUDIT +- audit_logger (AUDIT_DEL_USER, Prog, +- "locking shadow password file", +- user_name, (unsigned int) user_id, +- SHADOW_AUDIT_FAILURE); +-#endif /* WITH_AUDIT */ + fail_exit (E_PW_UPDATE); + } + spw_locked = true; +@@ -600,12 +582,6 @@ static void open_files (void) + fprintf (stderr, + _("%s: cannot open %s\n"), + Prog, spw_dbname ()); +-#ifdef WITH_AUDIT +- audit_logger (AUDIT_DEL_USER, Prog, +- "opening shadow password file", +- user_name, (unsigned int) user_id, +- SHADOW_AUDIT_FAILURE); +-#endif /* WITH_AUDIT */ + fail_exit (E_PW_UPDATE); + } + } +@@ -613,23 +589,11 @@ static void open_files (void) + fprintf (stderr, + _("%s: cannot lock %s; try again later.\n"), + Prog, gr_dbname ()); +-#ifdef WITH_AUDIT +- audit_logger (AUDIT_DEL_USER, Prog, +- "locking group file", +- user_name, (unsigned int) user_id, +- SHADOW_AUDIT_FAILURE); +-#endif /* WITH_AUDIT */ + fail_exit (E_GRP_UPDATE); + } + gr_locked = true; + if (gr_open (O_CREAT | O_RDWR) == 0) { + fprintf (stderr, _("%s: cannot open %s\n"), Prog, gr_dbname ()); +-#ifdef WITH_AUDIT +- audit_logger (AUDIT_DEL_USER, Prog, +- "opening group file", +- user_name, (unsigned int) user_id, +- SHADOW_AUDIT_FAILURE); +-#endif /* WITH_AUDIT */ + fail_exit (E_GRP_UPDATE); + } + #ifdef SHADOWGRP +@@ -638,24 +602,12 @@ static void open_files (void) + fprintf (stderr, + _("%s: cannot lock %s; try again later.\n"), + Prog, sgr_dbname ()); +-#ifdef WITH_AUDIT +- audit_logger (AUDIT_DEL_USER, Prog, +- "locking shadow group file", +- user_name, (unsigned int) user_id, +- SHADOW_AUDIT_FAILURE); +-#endif /* WITH_AUDIT */ + fail_exit (E_GRP_UPDATE); + } + sgr_locked= true; + if (sgr_open (O_CREAT | O_RDWR) == 0) { + fprintf (stderr, _("%s: cannot open %s\n"), + Prog, sgr_dbname ()); +-#ifdef WITH_AUDIT +- audit_logger (AUDIT_DEL_USER, Prog, +- "opening shadow group file", +- user_name, (unsigned int) user_id, +- SHADOW_AUDIT_FAILURE); +-#endif /* WITH_AUDIT */ + fail_exit (E_GRP_UPDATE); + } + } +@@ -666,24 +618,12 @@ static void open_files (void) + fprintf (stderr, + _("%s: cannot lock %s; try again later.\n"), + Prog, sub_uid_dbname ()); +-#ifdef WITH_AUDIT +- audit_logger (AUDIT_DEL_USER, Prog, +- "locking subordinate user file", +- user_name, (unsigned int) user_id, +- SHADOW_AUDIT_FAILURE); +-#endif /* WITH_AUDIT */ + fail_exit (E_SUB_UID_UPDATE); + } + sub_uid_locked = true; + if (sub_uid_open (O_CREAT | O_RDWR) == 0) { + fprintf (stderr, + _("%s: cannot open %s\n"), Prog, sub_uid_dbname ()); +-#ifdef WITH_AUDIT +- audit_logger (AUDIT_DEL_USER, Prog, +- "opening subordinate user file", +- user_name, (unsigned int) user_id, +- SHADOW_AUDIT_FAILURE); +-#endif /* WITH_AUDIT */ + fail_exit (E_SUB_UID_UPDATE); + } + } +@@ -692,24 +632,12 @@ static void open_files (void) + fprintf (stderr, + _("%s: cannot lock %s; try again later.\n"), + Prog, sub_gid_dbname ()); +-#ifdef WITH_AUDIT +- audit_logger (AUDIT_DEL_USER, Prog, +- "locking subordinate group file", +- user_name, (unsigned int) user_id, +- SHADOW_AUDIT_FAILURE); +-#endif /* WITH_AUDIT */ + fail_exit (E_SUB_GID_UPDATE); + } + sub_gid_locked = true; + if (sub_gid_open (O_CREAT | O_RDWR) == 0) { + fprintf (stderr, + _("%s: cannot open %s\n"), Prog, sub_gid_dbname ()); +-#ifdef WITH_AUDIT +- audit_logger (AUDIT_DEL_USER, Prog, +- "opening subordinate group file", +- user_name, (unsigned int) user_id, +- SHADOW_AUDIT_FAILURE); +-#endif /* WITH_AUDIT */ + fail_exit (E_SUB_GID_UPDATE); + } + } +@@ -754,7 +682,7 @@ static void update_user (void) + #endif /* ENABLE_SUBIDS */ + #ifdef WITH_AUDIT + audit_logger (AUDIT_DEL_USER, Prog, +- "deleting user entries", ++ "delete-user", + user_name, (unsigned int) user_id, + SHADOW_AUDIT_SUCCESS); + #endif /* WITH_AUDIT */ +@@ -862,7 +790,7 @@ static int remove_mailbox (void) + SYSLOG ((LOG_ERR, "Cannot remove %s: %s", mailfile, strerror (errno))); + #ifdef WITH_AUDIT + audit_logger (AUDIT_DEL_USER, Prog, +- "deleting mail file", ++ "delete-mail-file", + user_name, (unsigned int) user_id, + SHADOW_AUDIT_FAILURE); + #endif /* WITH_AUDIT */ +@@ -879,7 +807,7 @@ static int remove_mailbox (void) + SYSLOG ((LOG_ERR, "Cannot remove %s: %s", mailfile, strerror (errno))); + #ifdef WITH_AUDIT + audit_logger (AUDIT_DEL_USER, Prog, +- "deleting mail file", ++ "delete-mail-file", + user_name, (unsigned int) user_id, + SHADOW_AUDIT_FAILURE); + #endif /* WITH_AUDIT */ +@@ -889,8 +817,8 @@ static int remove_mailbox (void) + #ifdef WITH_AUDIT + else + { +- audit_logger (AUDIT_DEL_USER, Prog, +- "deleting mail file", ++ audit_logger (AUDIT_USER_MGMT, Prog, ++ "delete-mail-file", + user_name, (unsigned int) user_id, + SHADOW_AUDIT_SUCCESS); + } +@@ -908,7 +836,7 @@ static int remove_mailbox (void) + mailfile, strerror (errno))); + #ifdef WITH_AUDIT + audit_logger (AUDIT_DEL_USER, Prog, +- "deleting mail file", ++ "delete-mail-file", + user_name, (unsigned int) user_id, + SHADOW_AUDIT_FAILURE); + #endif /* WITH_AUDIT */ +@@ -925,7 +853,7 @@ static int remove_mailbox (void) + SYSLOG ((LOG_ERR, "Cannot remove %s: %s", mailfile, strerror (errno))); + #ifdef WITH_AUDIT + audit_logger (AUDIT_DEL_USER, Prog, +- "deleting mail file", ++ "delete-mail-file", + user_name, (unsigned int) user_id, + SHADOW_AUDIT_FAILURE); + #endif /* WITH_AUDIT */ +@@ -935,8 +863,8 @@ static int remove_mailbox (void) + #ifdef WITH_AUDIT + else + { +- audit_logger (AUDIT_DEL_USER, Prog, +- "deleting mail file", ++ audit_logger (AUDIT_USER_MGMT, Prog, ++ "delete-mail-file", + user_name, (unsigned int) user_id, + SHADOW_AUDIT_SUCCESS); + } +@@ -1149,7 +1077,7 @@ int main (int argc, char **argv) + Prog, user_name); + #ifdef WITH_AUDIT + audit_logger (AUDIT_DEL_USER, Prog, +- "deleting user not found", ++ "deleting-user-not-found", + user_name, AUDIT_NO_ID, + SHADOW_AUDIT_FAILURE); + #endif /* WITH_AUDIT */ +@@ -1205,7 +1133,7 @@ int main (int argc, char **argv) + if (!fflg) { + #ifdef WITH_AUDIT + audit_logger (AUDIT_DEL_USER, Prog, +- "deleting user logged in", ++ "deleting-user-logged-in", + user_name, AUDIT_NO_ID, + SHADOW_AUDIT_FAILURE); + #endif /* WITH_AUDIT */ +@@ -1282,8 +1210,8 @@ int main (int argc, char **argv) + #ifdef WITH_AUDIT + else + { +- audit_logger (AUDIT_DEL_USER, Prog, +- "deleting home directory", ++ audit_logger (AUDIT_USER_MGMT, Prog, ++ "deleting-home-directory", + user_name, (unsigned int) user_id, + SHADOW_AUDIT_SUCCESS); + } +@@ -1292,7 +1220,7 @@ int main (int argc, char **argv) + #ifdef WITH_AUDIT + if (0 != errors) { + audit_logger (AUDIT_DEL_USER, Prog, +- "deleting home directory", ++ "deleting-home-directory", + user_name, AUDIT_NO_ID, + SHADOW_AUDIT_FAILURE); + } +@@ -1305,8 +1233,8 @@ int main (int argc, char **argv) + _("%s: warning: the user name %s to SELinux user mapping removal failed.\n"), + Prog, user_name); + #ifdef WITH_AUDIT +- audit_logger (AUDIT_ADD_USER, Prog, +- "removing SELinux user mapping", ++ audit_logger (AUDIT_ROLE_REMOVE, Prog, ++ "delete-selinux-user-mapping", + user_name, (unsigned int) user_id, + SHADOW_AUDIT_FAILURE); + #endif /* WITH_AUDIT */ +diff -up shadow-4.6/src/usermod.c.audit-update shadow-4.6/src/usermod.c +--- shadow-4.6/src/usermod.c.audit-update 2018-05-28 15:01:09.912717543 +0200 ++++ shadow-4.6/src/usermod.c 2018-05-28 15:08:25.424969050 +0200 +@@ -453,8 +453,8 @@ static char *new_pw_passwd (char *pw_pas + + #ifdef WITH_AUDIT + audit_logger (AUDIT_USER_CHAUTHTOK, Prog, +- "updating passwd", +- user_newname, (unsigned int) user_newid, 0); ++ "updating-password", ++ user_newname, (unsigned int) user_newid, 1); + #endif + SYSLOG ((LOG_INFO, "lock user '%s' password", user_newname)); + strcpy (buf, "!"); +@@ -473,8 +473,8 @@ static char *new_pw_passwd (char *pw_pas + + #ifdef WITH_AUDIT + audit_logger (AUDIT_USER_CHAUTHTOK, Prog, +- "updating password", +- user_newname, (unsigned int) user_newid, 0); ++ "updating-password", ++ user_newname, (unsigned int) user_newid, 1); + #endif + SYSLOG ((LOG_INFO, "unlock user '%s' password", user_newname)); + s = pw_pass; +@@ -485,7 +485,7 @@ static char *new_pw_passwd (char *pw_pas + } else if (pflg) { + #ifdef WITH_AUDIT + audit_logger (AUDIT_USER_CHAUTHTOK, Prog, +- "changing password", ++ "updating-password", + user_newname, (unsigned int) user_newid, 1); + #endif + SYSLOG ((LOG_INFO, "change user '%s' password", user_newname)); +@@ -514,8 +514,8 @@ static void new_pwent (struct passwd *pw + fail_exit (E_NAME_IN_USE); + } + #ifdef WITH_AUDIT +- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, +- "changing name", ++ audit_logger (AUDIT_USER_MGMT, Prog, ++ "changing-name", + user_newname, (unsigned int) user_newid, 1); + #endif + SYSLOG ((LOG_INFO, +@@ -535,8 +535,8 @@ static void new_pwent (struct passwd *pw + + if (uflg) { + #ifdef WITH_AUDIT +- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, +- "changing uid", ++ audit_logger (AUDIT_USER_MGMT, Prog, ++ "changing-uid", + user_newname, (unsigned int) user_newid, 1); + #endif + SYSLOG ((LOG_INFO, +@@ -546,8 +546,8 @@ static void new_pwent (struct passwd *pw + } + if (gflg) { + #ifdef WITH_AUDIT +- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, +- "changing primary group", ++ audit_logger (AUDIT_USER_MGMT, Prog, ++ "changing-primary-group", + user_newname, (unsigned int) user_newid, 1); + #endif + SYSLOG ((LOG_INFO, +@@ -557,8 +557,8 @@ static void new_pwent (struct passwd *pw + } + if (cflg) { + #ifdef WITH_AUDIT +- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, +- "changing comment", ++ audit_logger (AUDIT_USER_MGMT, Prog, ++ "changing-comment", + user_newname, (unsigned int) user_newid, 1); + #endif + pwent->pw_gecos = user_newcomment; +@@ -566,8 +566,8 @@ static void new_pwent (struct passwd *pw + + if (dflg) { + #ifdef WITH_AUDIT +- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, +- "changing home directory", ++ audit_logger (AUDIT_USER_MGMT, Prog, ++ "changing-home-dir", + user_newname, (unsigned int) user_newid, 1); + #endif + SYSLOG ((LOG_INFO, +@@ -577,8 +577,8 @@ static void new_pwent (struct passwd *pw + } + if (sflg) { + #ifdef WITH_AUDIT +- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, +- "changing user shell", ++ audit_logger (AUDIT_USER_MGMT, Prog, ++ "changing-shell", + user_newname, (unsigned int) user_newid, 1); + #endif + SYSLOG ((LOG_INFO, +@@ -608,8 +608,8 @@ static void new_spent (struct spwd *spen + + if (fflg) { + #ifdef WITH_AUDIT +- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, +- "changing inactive days", ++ audit_logger (AUDIT_USER_MGMT, Prog, ++ "changing-inactive-days", + user_newname, (unsigned int) user_newid, 1); + #endif + SYSLOG ((LOG_INFO, +@@ -625,8 +625,8 @@ static void new_spent (struct spwd *spen + date_to_str (old_exp, sizeof(old_exp), + user_expire * DAY); + #ifdef WITH_AUDIT +- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, +- "changing expiration date", ++ audit_logger (AUDIT_USER_MGMT, Prog, ++ "changing-expiration-date", + user_newname, (unsigned int) user_newid, 1); + #endif + SYSLOG ((LOG_INFO, +@@ -709,9 +709,9 @@ static /*@noreturn@*/void fail_exit (int + #endif /* ENABLE_SUBIDS */ + + #ifdef WITH_AUDIT +- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, +- "modifying account", +- user_name, AUDIT_NO_ID, 0); ++ audit_logger (AUDIT_USER_MGMT, Prog, ++ "modify-account", ++ user_name, AUDIT_NO_ID, SHADOW_AUDIT_FAILURE); + #endif + exit (code); + } +@@ -765,9 +765,12 @@ static void update_group (void) + user_newname); + changed = true; + #ifdef WITH_AUDIT +- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, +- "changing group member", +- user_newname, AUDIT_NO_ID, 1); ++ audit_logger_with_group ( ++ AUDIT_USER_MGMT, Prog, ++ "update-member-in-group", ++ user_newname, AUDIT_NO_ID, ++ ngrp->gr_name, ++ SHADOW_AUDIT_SUCCESS); + #endif + SYSLOG ((LOG_INFO, + "change '%s' to '%s' in group '%s'", +@@ -781,9 +784,11 @@ static void update_group (void) + ngrp->gr_mem = del_list (ngrp->gr_mem, user_name); + changed = true; + #ifdef WITH_AUDIT +- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, +- "removing group member", +- user_name, AUDIT_NO_ID, 1); ++ audit_logger_with_group (AUDIT_USER_MGMT, Prog, ++ "delete-user-from-group", ++ user_name, AUDIT_NO_ID, ++ ngrp->gr_name, ++ SHADOW_AUDIT_SUCCESS); + #endif + SYSLOG ((LOG_INFO, + "delete '%s' from group '%s'", +@@ -796,9 +801,11 @@ static void update_group (void) + ngrp->gr_mem = add_list (ngrp->gr_mem, user_newname); + changed = true; + #ifdef WITH_AUDIT +- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, +- "adding user to group", +- user_name, AUDIT_NO_ID, 1); ++ audit_logger_with_group (AUDIT_USER_MGMT, Prog, ++ "add-user-to-group", ++ user_name, AUDIT_NO_ID, ++ ngrp->gr_name, ++ SHADOW_AUDIT_SUCCESS); + #endif + SYSLOG ((LOG_INFO, "add '%s' to group '%s'", + user_newname, ngrp->gr_name)); +@@ -873,9 +880,10 @@ static void update_gshadow (void) + nsgrp->sg_adm = add_list (nsgrp->sg_adm, user_newname); + changed = true; + #ifdef WITH_AUDIT +- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, +- "changing admin name in shadow group", +- user_name, AUDIT_NO_ID, 1); ++ audit_logger_with_group (AUDIT_GRP_MGMT, Prog, ++ "update-admin-name-in-shadow-group", ++ user_name, AUDIT_NO_ID, nsgrp->sg_name, ++ SHADOW_AUDIT_SUCCESS); + #endif + SYSLOG ((LOG_INFO, + "change admin '%s' to '%s' in shadow group '%s'", +@@ -895,9 +903,10 @@ static void update_gshadow (void) + user_newname); + changed = true; + #ifdef WITH_AUDIT +- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, +- "changing member in shadow group", +- user_name, AUDIT_NO_ID, 1); ++ audit_logger_with_group (AUDIT_USER_MGMT, Prog, ++ "update-member-in-shadow-group", ++ user_name, AUDIT_NO_ID, ++ nsgrp->sg_name, 1); + #endif + SYSLOG ((LOG_INFO, + "change '%s' to '%s' in shadow group '%s'", +@@ -911,9 +920,10 @@ static void update_gshadow (void) + nsgrp->sg_mem = del_list (nsgrp->sg_mem, user_name); + changed = true; + #ifdef WITH_AUDIT +- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, +- "removing user from shadow group", +- user_name, AUDIT_NO_ID, 1); ++ audit_logger_with_group (AUDIT_USER_MGMT, Prog, ++ "delete-user-from-shadow-group", ++ user_name, AUDIT_NO_ID, ++ nsgrp->sg_name, 1); + #endif + SYSLOG ((LOG_INFO, + "delete '%s' from shadow group '%s'", +@@ -926,9 +936,10 @@ static void update_gshadow (void) + nsgrp->sg_mem = add_list (nsgrp->sg_mem, user_newname); + changed = true; + #ifdef WITH_AUDIT +- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, +- "adding user to shadow group", +- user_newname, AUDIT_NO_ID, 1); ++ audit_logger_with_group (AUDIT_USER_MGMT, Prog, ++ "add-user-to-shadow-group", ++ user_newname, AUDIT_NO_ID, ++ nsgrp->sg_name, 1); + #endif + SYSLOG ((LOG_INFO, "add '%s' to shadow group '%s'", + user_newname, nsgrp->sg_name)); +@@ -1789,8 +1800,8 @@ static void move_home (void) + + #ifdef WITH_AUDIT + if (uflg || gflg) { +- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, +- "changing home directory owner", ++ audit_logger (AUDIT_USER_MGMT, Prog, ++ "updating-home-dir-owner", + user_newname, (unsigned int) user_newid, 1); + } + #endif +@@ -1808,8 +1819,8 @@ static void move_home (void) + fail_exit (E_HOMEDIR); + } + #ifdef WITH_AUDIT +- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, +- "moving home directory", ++ audit_logger (AUDIT_USER_MGMT, Prog, ++ "moving-home-dir", + user_newname, (unsigned int) user_newid, + 1); + #endif +@@ -1828,9 +1839,9 @@ static void move_home (void) + Prog, prefix_user_home); + } + #ifdef WITH_AUDIT +- audit_logger (AUDIT_USER_CHAUTHTOK, ++ audit_logger (AUDIT_USER_MGMT, + Prog, +- "moving home directory", ++ "moving-home-dir", + user_newname, + (unsigned int) user_newid, + 1); +@@ -2045,8 +2056,8 @@ static void move_mailbox (void) + } + #ifdef WITH_AUDIT + else { +- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, +- "changing mail file owner", ++ audit_logger (AUDIT_USER_MGMT, Prog, ++ "updating-mail-file-owner", + user_newname, (unsigned int) user_newid, 1); + } + #endif +@@ -2072,8 +2083,8 @@ static void move_mailbox (void) + } + #ifdef WITH_AUDIT + else { +- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, +- "changing mail file name", ++ audit_logger (AUDIT_USER_MGMT, Prog, ++ "updating-mail-file-name", + user_newname, (unsigned int) user_newid, 1); + } + #endif +@@ -2267,8 +2278,8 @@ int main (int argc, char **argv) + _("%s: warning: the user name %s to %s SELinux user mapping failed.\n"), + Prog, user_name, user_selinux); + #ifdef WITH_AUDIT +- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, +- "modifying User mapping ", ++ audit_logger (AUDIT_ROLE_ASSIGN, Prog, ++ "changing-selinux-user-mapping ", + user_name, (unsigned int) user_id, + SHADOW_AUDIT_FAILURE); + #endif /* WITH_AUDIT */ +@@ -2280,8 +2291,8 @@ int main (int argc, char **argv) + _("%s: warning: the user name %s to SELinux user mapping removal failed.\n"), + Prog, user_name); + #ifdef WITH_AUDIT +- audit_logger (AUDIT_ADD_USER, Prog, +- "removing SELinux user mapping", ++ audit_logger (AUDIT_ROLE_REMOVE, Prog, ++ "delete-selinux-user-mapping", + user_name, (unsigned int) user_id, + SHADOW_AUDIT_FAILURE); + #endif /* WITH_AUDIT */ +@@ -2319,8 +2330,8 @@ int main (int argc, char **argv) + */ + #ifdef WITH_AUDIT + if (uflg || gflg) { +- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, +- "changing home directory owner", ++ audit_logger (AUDIT_USER_MGMT, Prog, ++ "updating-home-dir-owner", + user_newname, (unsigned int) user_newid, 1); + } + #endif diff --git a/SOURCES/shadow-4.6-check-local-groups.patch b/SOURCES/shadow-4.6-check-local-groups.patch new file mode 100644 index 0000000..6e9d2bf --- /dev/null +++ b/SOURCES/shadow-4.6-check-local-groups.patch @@ -0,0 +1,642 @@ +From 140510de9de4771feb3af1d859c09604043a4c9b Mon Sep 17 00:00:00 2001 +From: ikerexxe +Date: Fri, 27 Mar 2020 14:23:02 +0100 +Subject: [PATCH 1/2] usermod: check only local groups with -G option + +Check only local groups when adding new supplementary groups to a user + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1727236 +--- + src/usermod.c | 220 ++++++++++++++++++++++++++++++++------------------ + 1 file changed, 143 insertions(+), 77 deletions(-) + +diff --git a/src/usermod.c b/src/usermod.c +index 05b98715..ef430296 100644 +--- a/src/usermod.c ++++ b/src/usermod.c +@@ -183,6 +183,7 @@ static bool sub_gid_locked = false; + static void date_to_str (/*@unique@*//*@out@*/char *buf, size_t maxsize, + long int date); + static int get_groups (char *); ++static struct group * get_local_group (char * grp_name); + static /*@noreturn@*/void usage (int status); + static void new_pwent (struct passwd *); + static void new_spent (struct spwd *); +@@ -196,7 +197,9 @@ static void grp_update (void); + + static void process_flags (int, char **); + static void close_files (void); ++static void close_group_files (void); + static void open_files (void); ++static void open_group_files (void); + static void usr_update (void); + static void move_home (void); + static void update_lastlog (void); +@@ -253,6 +256,11 @@ static int get_groups (char *list) + return 0; + } + ++ /* ++ * Open the group files ++ */ ++ open_group_files (); ++ + /* + * So long as there is some data to be converted, strip off each + * name and look it up. A mix of numerical and string values for +@@ -272,7 +280,7 @@ static int get_groups (char *list) + * Names starting with digits are treated as numerical GID + * values, otherwise the string is looked up as is. + */ +- grp = prefix_getgr_nam_gid (list); ++ grp = get_local_group (list); + + /* + * There must be a match, either by GID value or by +@@ -322,6 +330,8 @@ static int get_groups (char *list) + gr_free ((struct group *)grp); + } while (NULL != list); + ++ close_group_files (); ++ + user_groups[ngroups] = (char *) 0; + + /* +@@ -334,6 +344,44 @@ static int get_groups (char *list) + return 0; + } + ++/* ++ * get_local_group - checks if a given group name exists locally ++ * ++ * get_local_group() checks if a given group name exists locally. ++ * If the name exists the group information is returned, otherwise NULL is ++ * returned. ++ */ ++static struct group * get_local_group(char * grp_name) ++{ ++ const struct group *grp; ++ struct group *result_grp = NULL; ++ long long int gid; ++ char *endptr; ++ ++ gid = strtoll (grp_name, &endptr, 10); ++ if ( ('\0' != *grp_name) ++ && ('\0' == *endptr) ++ && (ERANGE != errno) ++ && (gid == (gid_t)gid)) { ++ grp = gr_locate_gid ((gid_t) gid); ++ } ++ else { ++ grp = gr_locate(grp_name); ++ } ++ ++ if (grp != NULL) { ++ result_grp = __gr_dup (grp); ++ if (NULL == result_grp) { ++ fprintf (stderr, ++ _("%s: Out of memory. Cannot find group '%s'.\n"), ++ Prog, grp_name); ++ fail_exit (E_GRP_UPDATE); ++ } ++ } ++ ++ return result_grp; ++} ++ + #ifdef ENABLE_SUBIDS + struct ulong_range + { +@@ -1447,50 +1495,7 @@ static void close_files (void) + } + + if (Gflg || lflg) { +- if (gr_close () == 0) { +- fprintf (stderr, +- _("%s: failure while writing changes to %s\n"), +- Prog, gr_dbname ()); +- SYSLOG ((LOG_ERR, +- "failure while writing changes to %s", +- gr_dbname ())); +- fail_exit (E_GRP_UPDATE); +- } +-#ifdef SHADOWGRP +- if (is_shadow_grp) { +- if (sgr_close () == 0) { +- fprintf (stderr, +- _("%s: failure while writing changes to %s\n"), +- Prog, sgr_dbname ()); +- SYSLOG ((LOG_ERR, +- "failure while writing changes to %s", +- sgr_dbname ())); +- fail_exit (E_GRP_UPDATE); +- } +- } +-#endif +-#ifdef SHADOWGRP +- if (is_shadow_grp) { +- if (sgr_unlock () == 0) { +- fprintf (stderr, +- _("%s: failed to unlock %s\n"), +- Prog, sgr_dbname ()); +- SYSLOG ((LOG_ERR, +- "failed to unlock %s", +- sgr_dbname ())); +- /* continue */ +- } +- } +-#endif +- if (gr_unlock () == 0) { +- fprintf (stderr, +- _("%s: failed to unlock %s\n"), +- Prog, gr_dbname ()); +- SYSLOG ((LOG_ERR, +- "failed to unlock %s", +- gr_dbname ())); +- /* continue */ +- } ++ close_group_files (); + } + + if (is_shadow_pwd) { +@@ -1559,6 +1564,60 @@ static void close_files (void) + #endif + } + ++/* ++ * close_group_files - close all of the files that were opened ++ * ++ * close_group_files() closes all of the files that were opened related ++ * with groups. This causes any modified entries to be written out. ++ */ ++static void close_group_files (void) ++{ ++ if (gr_close () == 0) { ++ fprintf (stderr, ++ _("%s: failure while writing changes to %s\n"), ++ Prog, gr_dbname ()); ++ SYSLOG ((LOG_ERR, ++ "failure while writing changes to %s", ++ gr_dbname ())); ++ fail_exit (E_GRP_UPDATE); ++ } ++#ifdef SHADOWGRP ++ if (is_shadow_grp) { ++ if (sgr_close () == 0) { ++ fprintf (stderr, ++ _("%s: failure while writing changes to %s\n"), ++ Prog, sgr_dbname ()); ++ SYSLOG ((LOG_ERR, ++ "failure while writing changes to %s", ++ sgr_dbname ())); ++ fail_exit (E_GRP_UPDATE); ++ } ++ } ++#endif ++#ifdef SHADOWGRP ++ if (is_shadow_grp) { ++ if (sgr_unlock () == 0) { ++ fprintf (stderr, ++ _("%s: failed to unlock %s\n"), ++ Prog, sgr_dbname ()); ++ SYSLOG ((LOG_ERR, ++ "failed to unlock %s", ++ sgr_dbname ())); ++ /* continue */ ++ } ++ } ++#endif ++ if (gr_unlock () == 0) { ++ fprintf (stderr, ++ _("%s: failed to unlock %s\n"), ++ Prog, gr_dbname ()); ++ SYSLOG ((LOG_ERR, ++ "failed to unlock %s", ++ gr_dbname ())); ++ /* continue */ ++ } ++} ++ + /* + * open_files - lock and open the password files + * +@@ -1594,38 +1653,7 @@ static void open_files (void) + } + + if (Gflg || lflg) { +- /* +- * Lock and open the group file. This will load all of the +- * group entries. +- */ +- if (gr_lock () == 0) { +- fprintf (stderr, +- _("%s: cannot lock %s; try again later.\n"), +- Prog, gr_dbname ()); +- fail_exit (E_GRP_UPDATE); +- } +- gr_locked = true; +- if (gr_open (O_CREAT | O_RDWR) == 0) { +- fprintf (stderr, +- _("%s: cannot open %s\n"), +- Prog, gr_dbname ()); +- fail_exit (E_GRP_UPDATE); +- } +-#ifdef SHADOWGRP +- if (is_shadow_grp && (sgr_lock () == 0)) { +- fprintf (stderr, +- _("%s: cannot lock %s; try again later.\n"), +- Prog, sgr_dbname ()); +- fail_exit (E_GRP_UPDATE); +- } +- sgr_locked = true; +- if (is_shadow_grp && (sgr_open (O_CREAT | O_RDWR) == 0)) { +- fprintf (stderr, +- _("%s: cannot open %s\n"), +- Prog, sgr_dbname ()); +- fail_exit (E_GRP_UPDATE); +- } +-#endif ++ open_group_files (); + } + #ifdef ENABLE_SUBIDS + if (vflg || Vflg) { +@@ -1661,6 +1689,44 @@ static void open_files (void) + #endif /* ENABLE_SUBIDS */ + } + ++/* ++ * open_group_files - lock and open the group files ++ * ++ * open_group_files() loads all of the group entries. ++ */ ++static void open_group_files (void) ++{ ++ if (gr_lock () == 0) { ++ fprintf (stderr, ++ _("%s: cannot lock %s; try again later.\n"), ++ Prog, gr_dbname ()); ++ fail_exit (E_GRP_UPDATE); ++ } ++ gr_locked = true; ++ if (gr_open (O_CREAT | O_RDWR) == 0) { ++ fprintf (stderr, ++ _("%s: cannot open %s\n"), ++ Prog, gr_dbname ()); ++ fail_exit (E_GRP_UPDATE); ++ } ++ ++#ifdef SHADOWGRP ++ if (is_shadow_grp && (sgr_lock () == 0)) { ++ fprintf (stderr, ++ _("%s: cannot lock %s; try again later.\n"), ++ Prog, sgr_dbname ()); ++ fail_exit (E_GRP_UPDATE); ++ } ++ sgr_locked = true; ++ if (is_shadow_grp && (sgr_open (O_CREAT | O_RDWR) == 0)) { ++ fprintf (stderr, ++ _("%s: cannot open %s\n"), ++ Prog, sgr_dbname ()); ++ fail_exit (E_GRP_UPDATE); ++ } ++#endif ++} ++ + /* + * usr_update - create the user entries + * +-- +2.25.4 + + +From 8762f465d487a52bf68f9c0b7c3c1eb3caea7bc9 Mon Sep 17 00:00:00 2001 +From: ikerexxe +Date: Mon, 30 Mar 2020 09:08:23 +0200 +Subject: [PATCH 2/2] useradd: check only local groups with -G option + +Check only local groups when adding new supplementary groups to a user + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1727236 +--- + src/useradd.c | 234 +++++++++++++++++++++++++++++++++----------------- + 1 file changed, 157 insertions(+), 77 deletions(-) + +diff --git a/src/useradd.c b/src/useradd.c +index 645d4a40..90210233 100644 +--- a/src/useradd.c ++++ b/src/useradd.c +@@ -211,6 +211,7 @@ static void get_defaults (void); + static void show_defaults (void); + static int set_defaults (void); + static int get_groups (char *); ++static struct group * get_local_group (char * grp_name); + static void usage (int status); + static void new_pwent (struct passwd *); + +@@ -220,7 +221,10 @@ static void grp_update (void); + + static void process_flags (int argc, char **argv); + static void close_files (void); ++static void close_group_files (void); ++static void unlock_group_files (void); + static void open_files (void); ++static void open_group_files (void); + static void open_shadow (void); + static void faillog_reset (uid_t); + static void lastlog_reset (uid_t); +@@ -731,6 +735,11 @@ static int get_groups (char *list) + return 0; + } + ++ /* ++ * Open the group files ++ */ ++ open_group_files (); ++ + /* + * So long as there is some data to be converted, strip off + * each name and look it up. A mix of numerical and string +@@ -749,7 +758,7 @@ static int get_groups (char *list) + * Names starting with digits are treated as numerical + * GID values, otherwise the string is looked up as is. + */ +- grp = prefix_getgr_nam_gid (list); ++ grp = get_local_group (list); + + /* + * There must be a match, either by GID value or by +@@ -799,6 +808,9 @@ static int get_groups (char *list) + user_groups[ngroups++] = xstrdup (grp->gr_name); + } while (NULL != list); + ++ close_group_files (); ++ unlock_group_files (); ++ + user_groups[ngroups] = (char *) 0; + + /* +@@ -811,6 +823,44 @@ static int get_groups (char *list) + return 0; + } + ++/* ++ * get_local_group - checks if a given group name exists locally ++ * ++ * get_local_group() checks if a given group name exists locally. ++ * If the name exists the group information is returned, otherwise NULL is ++ * returned. ++ */ ++static struct group * get_local_group(char * grp_name) ++{ ++ const struct group *grp; ++ struct group *result_grp = NULL; ++ long long int gid; ++ char *endptr; ++ ++ gid = strtoll (grp_name, &endptr, 10); ++ if ( ('\0' != *grp_name) ++ && ('\0' == *endptr) ++ && (ERANGE != errno) ++ && (gid == (gid_t)gid)) { ++ grp = gr_locate_gid ((gid_t) gid); ++ } ++ else { ++ grp = gr_locate(grp_name); ++ } ++ ++ if (grp != NULL) { ++ result_grp = __gr_dup (grp); ++ if (NULL == result_grp) { ++ fprintf (stderr, ++ _("%s: Out of memory. Cannot find group '%s'.\n"), ++ Prog, grp_name); ++ fail_exit (E_GRP_UPDATE); ++ } ++ } ++ ++ return result_grp; ++} ++ + /* + * usage - display usage message and exit + */ +@@ -1530,23 +1580,9 @@ static void close_files (void) + SYSLOG ((LOG_ERR, "failure while writing changes to %s", spw_dbname ())); + fail_exit (E_PW_UPDATE); + } +- if (do_grp_update) { +- if (gr_close () == 0) { +- fprintf (stderr, +- _("%s: failure while writing changes to %s\n"), Prog, gr_dbname ()); +- SYSLOG ((LOG_ERR, "failure while writing changes to %s", gr_dbname ())); +- fail_exit (E_GRP_UPDATE); +- } +-#ifdef SHADOWGRP +- if (is_shadow_grp && (sgr_close () == 0)) { +- fprintf (stderr, +- _("%s: failure while writing changes to %s\n"), +- Prog, sgr_dbname ()); +- SYSLOG ((LOG_ERR, "failure while writing changes to %s", sgr_dbname ())); +- fail_exit (E_GRP_UPDATE); +- } +-#endif +- } ++ ++ close_group_files (); ++ + #ifdef ENABLE_SUBIDS + if (is_sub_uid && (sub_uid_close () == 0)) { + fprintf (stderr, +@@ -1587,34 +1623,9 @@ static void close_files (void) + /* continue */ + } + pw_locked = false; +- if (gr_unlock () == 0) { +- fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, gr_dbname ()); +- SYSLOG ((LOG_ERR, "failed to unlock %s", gr_dbname ())); +-#ifdef WITH_AUDIT +- audit_logger (AUDIT_ADD_USER, Prog, +- "unlocking-group-file", +- user_name, AUDIT_NO_ID, +- SHADOW_AUDIT_FAILURE); +-#endif +- /* continue */ +- } +- gr_locked = false; +-#ifdef SHADOWGRP +- if (is_shadow_grp) { +- if (sgr_unlock () == 0) { +- fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sgr_dbname ()); +- SYSLOG ((LOG_ERR, "failed to unlock %s", sgr_dbname ())); +-#ifdef WITH_AUDIT +- audit_logger (AUDIT_ADD_USER, Prog, +- "unlocking-gshadow-file", +- user_name, AUDIT_NO_ID, +- SHADOW_AUDIT_FAILURE); +-#endif +- /* continue */ +- } +- sgr_locked = false; +- } +-#endif ++ ++ unlock_group_files (); ++ + #ifdef ENABLE_SUBIDS + if (is_sub_uid) { + if (sub_uid_unlock () == 0) { +@@ -1647,6 +1658,71 @@ static void close_files (void) + #endif /* ENABLE_SUBIDS */ + } + ++/* ++ * close_group_files - close all of the files that were opened ++ * ++ * close_group_files() closes all of the files that were opened related ++ * with groups. This causes any modified entries to be written out. ++ */ ++static void close_group_files (void) ++{ ++ if (do_grp_update) { ++ if (gr_close () == 0) { ++ fprintf (stderr, ++ _("%s: failure while writing changes to %s\n"), Prog, gr_dbname ()); ++ SYSLOG ((LOG_ERR, "failure while writing changes to %s", gr_dbname ())); ++ fail_exit (E_GRP_UPDATE); ++ } ++#ifdef SHADOWGRP ++ if (is_shadow_grp && (sgr_close () == 0)) { ++ fprintf (stderr, ++ _("%s: failure while writing changes to %s\n"), ++ Prog, sgr_dbname ()); ++ SYSLOG ((LOG_ERR, "failure while writing changes to %s", sgr_dbname ())); ++ fail_exit (E_GRP_UPDATE); ++ } ++#endif /* SHADOWGRP */ ++ } ++} ++ ++/* ++ * unlock_group_files - unlock all of the files that were locked ++ * ++ * unlock_group_files() unlocks all of the files that were locked related ++ * with groups. This causes any modified entries to be written out. ++ */ ++static void unlock_group_files (void) ++{ ++ if (gr_unlock () == 0) { ++ fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, gr_dbname ()); ++ SYSLOG ((LOG_ERR, "failed to unlock %s", gr_dbname ())); ++#ifdef WITH_AUDIT ++ audit_logger (AUDIT_ADD_USER, Prog, ++ "unlocking-group-file", ++ user_name, AUDIT_NO_ID, ++ SHADOW_AUDIT_FAILURE); ++#endif /* WITH_AUDIT */ ++ /* continue */ ++ } ++ gr_locked = false; ++#ifdef SHADOWGRP ++ if (is_shadow_grp) { ++ if (sgr_unlock () == 0) { ++ fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sgr_dbname ()); ++ SYSLOG ((LOG_ERR, "failed to unlock %s", sgr_dbname ())); ++#ifdef WITH_AUDIT ++ audit_logger (AUDIT_ADD_USER, Prog, ++ "unlocking-gshadow-file", ++ user_name, AUDIT_NO_ID, ++ SHADOW_AUDIT_FAILURE); ++#endif /* WITH_AUDIT */ ++ /* continue */ ++ } ++ sgr_locked = false; ++ } ++#endif /* SHADOWGRP */ ++} ++ + /* + * open_files - lock and open the password files + * +@@ -1668,37 +1744,8 @@ static void open_files (void) + + /* shadow file will be opened by open_shadow(); */ + +- /* +- * Lock and open the group file. +- */ +- if (gr_lock () == 0) { +- fprintf (stderr, +- _("%s: cannot lock %s; try again later.\n"), +- Prog, gr_dbname ()); +- fail_exit (E_GRP_UPDATE); +- } +- gr_locked = true; +- if (gr_open (O_CREAT | O_RDWR) == 0) { +- fprintf (stderr, _("%s: cannot open %s\n"), Prog, gr_dbname ()); +- fail_exit (E_GRP_UPDATE); +- } +-#ifdef SHADOWGRP +- if (is_shadow_grp) { +- if (sgr_lock () == 0) { +- fprintf (stderr, +- _("%s: cannot lock %s; try again later.\n"), +- Prog, sgr_dbname ()); +- fail_exit (E_GRP_UPDATE); +- } +- sgr_locked = true; +- if (sgr_open (O_CREAT | O_RDWR) == 0) { +- fprintf (stderr, +- _("%s: cannot open %s\n"), +- Prog, sgr_dbname ()); +- fail_exit (E_GRP_UPDATE); +- } +- } +-#endif ++ open_group_files (); ++ + #ifdef ENABLE_SUBIDS + if (is_sub_uid) { + if (sub_uid_lock () == 0) { +@@ -1733,6 +1780,39 @@ static void open_files (void) + #endif /* ENABLE_SUBIDS */ + } + ++static void open_group_files (void) ++{ ++ if (gr_lock () == 0) { ++ fprintf (stderr, ++ _("%s: cannot lock %s; try again later.\n"), ++ Prog, gr_dbname ()); ++ fail_exit (E_GRP_UPDATE); ++ } ++ gr_locked = true; ++ if (gr_open (O_CREAT | O_RDWR) == 0) { ++ fprintf (stderr, _("%s: cannot open %s\n"), Prog, gr_dbname ()); ++ fail_exit (E_GRP_UPDATE); ++ } ++ ++#ifdef SHADOWGRP ++ if (is_shadow_grp) { ++ if (sgr_lock () == 0) { ++ fprintf (stderr, ++ _("%s: cannot lock %s; try again later.\n"), ++ Prog, sgr_dbname ()); ++ fail_exit (E_GRP_UPDATE); ++ } ++ sgr_locked = true; ++ if (sgr_open (O_CREAT | O_RDWR) == 0) { ++ fprintf (stderr, ++ _("%s: cannot open %s\n"), ++ Prog, sgr_dbname ()); ++ fail_exit (E_GRP_UPDATE); ++ } ++ } ++#endif /* SHADOWGRP */ ++} ++ + static void open_shadow (void) + { + if (!is_shadow_pwd) { +-- +2.25.4 + diff --git a/SOURCES/shadow-4.6-chgrp-guard.patch b/SOURCES/shadow-4.6-chgrp-guard.patch new file mode 100644 index 0000000..2918684 --- /dev/null +++ b/SOURCES/shadow-4.6-chgrp-guard.patch @@ -0,0 +1,44 @@ +diff -up shadow-4.6/man/usermod.8.xml.chgrp-guard shadow-4.6/man/usermod.8.xml +--- shadow-4.6/man/usermod.8.xml.chgrp-guard 2018-11-06 09:08:54.170095358 +0100 ++++ shadow-4.6/man/usermod.8.xml 2018-12-18 15:24:12.283181180 +0100 +@@ -195,6 +195,12 @@ + The group ownership of files outside of the user's home directory + must be fixed manually. + ++ ++ The change of the group ownership of files inside of the user's ++ home directory is also not done if the home dir owner uid is ++ different from the current or new user id. This is safety measure ++ for special home directories such as /. ++ + + + +@@ -372,6 +378,12 @@ + must be fixed manually. + + ++ The change of the user ownership of files inside of the user's ++ home directory is also not done if the home dir owner uid is ++ different from the current or new user id. This is safety measure ++ for special home directories such as /. ++ ++ + No checks will be performed with regard to the + , , + , or +diff -up shadow-4.6/src/usermod.c.chgrp-guard shadow-4.6/src/usermod.c +--- shadow-4.6/src/usermod.c.chgrp-guard 2018-12-18 15:24:12.286181249 +0100 ++++ shadow-4.6/src/usermod.c 2018-12-18 15:26:51.227841435 +0100 +@@ -2336,7 +2336,10 @@ int main (int argc, char **argv) + } + + if (!mflg && (uflg || gflg)) { +- if (access (dflg ? prefix_user_newhome : prefix_user_home, F_OK) == 0) { ++ struct stat sb; ++ ++ if (stat (dflg ? prefix_user_newhome : prefix_user_home, &sb) == 0 && ++ ((uflg && sb.st_uid == user_newid) || sb.st_uid == user_id)) { + /* + * Change the UID on all of the files owned by + * `user_id' to `user_newid' in the user's home diff --git a/SOURCES/shadow-4.6-coverity.patch b/SOURCES/shadow-4.6-coverity.patch new file mode 100644 index 0000000..44533e2 --- /dev/null +++ b/SOURCES/shadow-4.6-coverity.patch @@ -0,0 +1,223 @@ +diff -up shadow-4.6/lib/commonio.c.coverity shadow-4.6/lib/commonio.c +--- shadow-4.6/lib/commonio.c.coverity 2018-10-10 09:50:59.307738194 +0200 ++++ shadow-4.6/lib/commonio.c 2018-10-10 09:55:32.919319048 +0200 +@@ -382,7 +382,7 @@ int commonio_lock_nowait (struct commoni + char* lock = NULL; + size_t lock_file_len; + size_t file_len; +- int err; ++ int err = 0; + + if (db->locked) { + return 1; +@@ -391,12 +391,10 @@ int commonio_lock_nowait (struct commoni + lock_file_len = strlen(db->filename) + 6; /* sizeof ".lock" */ + file = (char*)malloc(file_len); + if(file == NULL) { +- err = ENOMEM; + goto cleanup_ENOMEM; + } + lock = (char*)malloc(lock_file_len); + if(lock == NULL) { +- err = ENOMEM; + goto cleanup_ENOMEM; + } + snprintf (file, file_len, "%s.%lu", +diff -up shadow-4.6/libmisc/console.c.coverity shadow-4.6/libmisc/console.c +--- shadow-4.6/libmisc/console.c.coverity 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/libmisc/console.c 2018-10-10 11:56:51.368837533 +0200 +@@ -50,7 +50,7 @@ static bool is_listed (const char *cfgin + static bool is_listed (const char *cfgin, const char *tty, bool def) + { + FILE *fp; +- char buf[200], *s; ++ char buf[1024], *s; + const char *cons; + + /* +@@ -70,7 +70,8 @@ static bool is_listed (const char *cfgin + + if (*cons != '/') { + char *pbuf; +- strcpy (buf, cons); ++ strncpy (buf, cons, sizeof (buf)); ++ buf[sizeof (buf) - 1] = '\0'; + pbuf = &buf[0]; + while ((s = strtok (pbuf, ":")) != NULL) { + if (strcmp (s, tty) == 0) { +diff -up shadow-4.6/lib/spawn.c.coverity shadow-4.6/lib/spawn.c +--- shadow-4.6/lib/spawn.c.coverity 2018-04-29 18:42:37.000000001 +0200 ++++ shadow-4.6/lib/spawn.c 2018-10-10 11:36:49.035784609 +0200 +@@ -69,7 +69,7 @@ int run_command (const char *cmd, const + do { + wpid = waitpid (pid, status, 0); + } while ( ((pid_t)-1 == wpid && errno == EINTR) +- || (wpid != pid)); ++ || ((pid_t)-1 != wpid && wpid != pid)); + + if ((pid_t)-1 == wpid) { + fprintf (stderr, "%s: waitpid (status: %d): %s\n", +diff -up shadow-4.6/src/useradd.c.coverity shadow-4.6/src/useradd.c +--- shadow-4.6/src/useradd.c.coverity 2018-10-10 09:50:59.303738098 +0200 ++++ shadow-4.6/src/useradd.c 2018-10-12 13:51:54.480490257 +0200 +@@ -314,7 +314,7 @@ static void fail_exit (int code) + static void get_defaults (void) + { + FILE *fp; +- char* default_file = USER_DEFAULTS_FILE; ++ char *default_file = USER_DEFAULTS_FILE; + char buf[1024]; + char *cp; + +@@ -324,6 +324,8 @@ static void get_defaults (void) + + len = strlen(prefix) + strlen(USER_DEFAULTS_FILE) + 2; + default_file = malloc(len); ++ if (default_file == NULL) ++ return; + wlen = snprintf(default_file, len, "%s/%s", prefix, USER_DEFAULTS_FILE); + assert (wlen == (int) len -1); + } +@@ -334,7 +336,7 @@ static void get_defaults (void) + + fp = fopen (default_file, "r"); + if (NULL == fp) { +- return; ++ goto getdef_err; + } + + /* +@@ -445,7 +447,7 @@ static void get_defaults (void) + } + } + (void) fclose (fp); +- ++ getdef_err: + if(prefix[0]) { + free(default_file); + } +@@ -480,8 +482,8 @@ static int set_defaults (void) + FILE *ifp; + FILE *ofp; + char buf[1024]; +- char* new_file = NEW_USER_FILE; +- char* default_file = USER_DEFAULTS_FILE; ++ char *new_file = NULL; ++ char *default_file = USER_DEFAULTS_FILE; + char *cp; + int ofd; + int wlen; +@@ -492,17 +494,30 @@ static int set_defaults (void) + bool out_shell = false; + bool out_skel = false; + bool out_create_mail_spool = false; ++ size_t len; ++ int ret = -1; + +- if(prefix[0]) { +- size_t len; + +- len = strlen(prefix) + strlen(NEW_USER_FILE) + 2; +- new_file = malloc(len); +- wlen = snprintf(new_file, len, "%s/%s", prefix, NEW_USER_FILE); +- assert (wlen == (int) len -1); ++ len = strlen(prefix) + strlen(NEW_USER_FILE) + 2; ++ new_file = malloc(len); ++ if (new_file == NULL) { ++ fprintf (stderr, ++ _("%s: cannot create new defaults file: %s\n"), ++ Prog, strerror(errno)); ++ return -1; ++ } ++ wlen = snprintf(new_file, len, "%s%s%s", prefix, prefix[0]?"/":"", NEW_USER_FILE); ++ assert (wlen <= (int) len -1); + ++ if(prefix[0]) { + len = strlen(prefix) + strlen(USER_DEFAULTS_FILE) + 2; + default_file = malloc(len); ++ if (default_file == NULL) { ++ fprintf (stderr, ++ _("%s: cannot create new defaults file: %s\n"), ++ Prog, strerror(errno)); ++ goto setdef_err; ++ } + wlen = snprintf(default_file, len, "%s/%s", prefix, USER_DEFAULTS_FILE); + assert (wlen == (int) len -1); + } +@@ -515,7 +530,7 @@ static int set_defaults (void) + fprintf (stderr, + _("%s: cannot create new defaults file\n"), + Prog); +- return -1; ++ goto setdef_err; + } + + ofp = fdopen (ofd, "w"); +@@ -523,7 +538,7 @@ static int set_defaults (void) + fprintf (stderr, + _("%s: cannot open new defaults file\n"), + Prog); +- return -1; ++ goto setdef_err; + } + + /* +@@ -550,7 +565,7 @@ static int set_defaults (void) + _("%s: line too long in %s: %s..."), + Prog, default_file, buf); + (void) fclose (ifp); +- return -1; ++ goto setdef_err; + } + } + +@@ -614,7 +629,7 @@ static int set_defaults (void) + || (fsync (fileno (ofp)) != 0) + || (fclose (ofp) != 0)) { + unlink (new_file); +- return -1; ++ goto setdef_err; + } + + /* +@@ -629,7 +644,7 @@ static int set_defaults (void) + _("%s: Cannot create backup file (%s): %s\n"), + Prog, buf, strerror (err)); + unlink (new_file); +- return -1; ++ goto setdef_err; + } + + /* +@@ -640,11 +655,11 @@ static int set_defaults (void) + fprintf (stderr, + _("%s: rename: %s: %s\n"), + Prog, new_file, strerror (err)); +- return -1; ++ goto setdef_err; + } + #ifdef WITH_AUDIT + audit_logger (AUDIT_USYS_CONFIG, Prog, +- "changing-useradd-defaults", ++ "changing useradd defaults", + NULL, AUDIT_NO_ID, + SHADOW_AUDIT_SUCCESS); + #endif +@@ -654,13 +669,14 @@ static int set_defaults (void) + (unsigned int) def_group, def_home, def_shell, + def_inactive, def_expire, def_template, + def_create_mail_spool)); +- ++ ret = 0; ++ setdef_err: ++ free(new_file); + if(prefix[0]) { +- free(new_file); + free(default_file); + } + +- return 0; ++ return ret; + } + + /* diff --git a/SOURCES/shadow-4.6-getenforce.patch b/SOURCES/shadow-4.6-getenforce.patch new file mode 100644 index 0000000..8a55bf5 --- /dev/null +++ b/SOURCES/shadow-4.6-getenforce.patch @@ -0,0 +1,21 @@ +diff -up shadow-4.6/lib/selinux.c.getenforce shadow-4.6/lib/selinux.c +--- shadow-4.6/lib/selinux.c.getenforce 2018-05-28 15:10:15.870315221 +0200 ++++ shadow-4.6/lib/selinux.c 2018-05-28 15:10:15.894315731 +0200 +@@ -75,7 +75,7 @@ int set_selinux_file_context (const char + } + return 0; + error: +- if (security_getenforce () != 0) { ++ if (security_getenforce () > 0) { + return 1; + } + return 0; +@@ -95,7 +95,7 @@ int reset_selinux_file_context (void) + selinux_checked = true; + } + if (selinux_enabled) { +- if (setfscreatecon (NULL) != 0) { ++ if (setfscreatecon (NULL) != 0 && security_getenforce () > 0) { + return 1; + } + } diff --git a/SOURCES/shadow-4.6-getsubids.patch b/SOURCES/shadow-4.6-getsubids.patch new file mode 100644 index 0000000..12030cb --- /dev/null +++ b/SOURCES/shadow-4.6-getsubids.patch @@ -0,0 +1,244 @@ +diff -up shadow-4.6/man/getsubids.1.xml.getsubids shadow-4.6/man/getsubids.1.xml +--- shadow-4.6/man/getsubids.1.xml.getsubids 2021-12-09 10:40:50.730275761 +0100 ++++ shadow-4.6/man/getsubids.1.xml 2021-12-09 10:40:50.730275761 +0100 +@@ -0,0 +1,141 @@ ++ ++ ++ ++]> ++ ++ ++ ++ ++ Iker ++ Pedrosa ++ Creation, 2021 ++ ++ ++ ++ getsubids ++ 1 ++ User Commands ++ shadow-utils ++ &SHADOW_UTILS_VERSION; ++ ++ ++ getsubids ++ get the subordinate id ranges for a user ++ ++ ++ ++ ++ getsubids ++ ++ options ++ ++ ++ USER ++ ++ ++ ++ ++ ++ DESCRIPTION ++ ++ The getsubids command lists the subordinate user ID ++ ranges for a given user. The subordinate group IDs can be listed using ++ the option. ++ ++ ++ ++ ++ OPTIONS ++ ++ The options which apply to the getsubids command are: ++ ++ ++ ++ ++ ++ ++ ++ ++ List the subordinate group ID ranges. ++ ++ ++ ++ ++ ++ ++ ++ EXAMPLE ++ ++ For example, to obtain the subordinate UIDs of the testuser: ++ ++ ++ ++$ getsubids testuser ++0: testuser 100000 65536 ++ ++ ++ ++ This command output provides (in order from left to right) the list ++ index, username, UID range start, and number of UIDs in range. ++ ++ ++ ++ ++ SEE ALSO ++ ++ ++ login.defs5 ++ , ++ ++ newgidmap1 ++ , ++ ++ newuidmap1 ++ , ++ ++ subgid5 ++ , ++ ++ subuid5 ++ , ++ ++ useradd8 ++ , ++ ++ userdel8 ++ . ++ ++ usermod8 ++ , ++ ++ ++ +diff -up shadow-4.6/man/Makefile.am.getsubids shadow-4.6/man/Makefile.am +--- shadow-4.6/man/Makefile.am.getsubids 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/man/Makefile.am 2021-12-09 10:40:50.730275761 +0100 +@@ -59,6 +59,7 @@ man_MANS += $(man_nopam) + endif + + man_subids = \ ++ man1/getsubids.1 \ + man1/newgidmap.1 \ + man1/newuidmap.1 \ + man5/subgid.5 \ +@@ -77,6 +78,7 @@ man_XMANS = \ + expiry.1.xml \ + faillog.5.xml \ + faillog.8.xml \ ++ getsubids.1.xml \ + gpasswd.1.xml \ + groupadd.8.xml \ + groupdel.8.xml \ +diff -up shadow-4.6/src/getsubids.c.getsubids shadow-4.6/src/getsubids.c +--- shadow-4.6/src/getsubids.c.getsubids 2021-12-09 10:40:50.730275761 +0100 ++++ shadow-4.6/src/getsubids.c 2021-12-09 10:40:50.730275761 +0100 +@@ -0,0 +1,46 @@ ++#include ++#include ++#include ++#include "subid.h" ++#include "prototypes.h" ++ ++const char *Prog; ++FILE *shadow_logfd = NULL; ++ ++void usage(void) ++{ ++ fprintf(stderr, "Usage: %s [-g] user\n", Prog); ++ fprintf(stderr, " list subuid ranges for user\n"); ++ fprintf(stderr, " pass -g to list subgid ranges\n"); ++ exit(EXIT_FAILURE); ++} ++ ++int main(int argc, char *argv[]) ++{ ++ int i, count=0; ++ struct subid_range *ranges; ++ const char *owner; ++ ++ Prog = Basename (argv[0]); ++ shadow_logfd = stderr; ++ if (argc < 2) ++ usage(); ++ owner = argv[1]; ++ if (argc == 3 && strcmp(argv[1], "-g") == 0) { ++ owner = argv[2]; ++ count = get_subgid_ranges(owner, &ranges); ++ } else if (argc == 2 && strcmp(argv[1], "-h") == 0) { ++ usage(); ++ } else { ++ count = get_subuid_ranges(owner, &ranges); ++ } ++ if (!ranges) { ++ fprintf(stderr, "Error fetching ranges\n"); ++ exit(1); ++ } ++ for (i = 0; i < count; i++) { ++ printf("%d: %s %lu %lu\n", i, owner, ++ ranges[i].start, ranges[i].count); ++ } ++ return 0; ++} +diff -up shadow-4.6/src/Makefile.am.getsubids shadow-4.6/src/Makefile.am +--- shadow-4.6/src/Makefile.am.getsubids 2021-12-09 10:40:50.710275627 +0100 ++++ shadow-4.6/src/Makefile.am 2021-12-09 10:45:04.465985510 +0100 +@@ -140,8 +140,8 @@ if WITH_TCB + endif + + if ENABLE_SUBIDS +-noinst_PROGRAMS += list_subid_ranges \ +- get_subid_owners \ ++bin_PROGRAMS += getsubids ++noinst_PROGRAMS += get_subid_owners \ + new_subid_range \ + free_subid_range \ + check_subid_range +@@ -156,13 +156,13 @@ MISCLIBS = \ + $(LIBCRYPT) \ + $(LIBTCB) + +-list_subid_ranges_LDADD = \ ++getsubids_LDADD = \ + $(top_builddir)/lib/libshadow.la \ + $(top_builddir)/libmisc/libmisc.la \ + $(top_builddir)/libsubid/libsubid.la \ + $(MISCLIBS) -ldl + +-list_subid_ranges_CPPFLAGS = \ ++getsubids_CPPFLAGS = \ + -I$(top_srcdir)/lib \ + -I$(top_srcdir)/libmisc \ + -I$(top_srcdir)/libsubid diff --git a/SOURCES/shadow-4.6-goodname.patch b/SOURCES/shadow-4.6-goodname.patch new file mode 100644 index 0000000..13b5f75 --- /dev/null +++ b/SOURCES/shadow-4.6-goodname.patch @@ -0,0 +1,104 @@ +diff -up shadow-4.6/libmisc/chkname.c.goodname shadow-4.6/libmisc/chkname.c +--- shadow-4.6/libmisc/chkname.c.goodname 2020-10-23 12:50:47.202529031 +0200 ++++ shadow-4.6/libmisc/chkname.c 2020-10-23 12:54:54.604692559 +0200 +@@ -49,25 +49,44 @@ + static bool is_valid_name (const char *name) + { + /* +- * User/group names must match [a-z_][a-z0-9_-]*[$] +- */ +- if (('\0' == *name) || +- !((('a' <= *name) && ('z' >= *name)) || ('_' == *name))) { ++ * User/group names must match gnu e-regex: ++ * [a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,30}[a-zA-Z0-9_.$-]? ++ * ++ * as a non-POSIX, extension, allow "$" as the last char for ++ * sake of Samba 3.x "add machine script" ++ * ++ * Also do not allow fully numeric names or just "." or "..". ++ */ ++ int numeric; ++ ++ if ('\0' == *name || ++ ('.' == *name && (('.' == name[1] && '\0' == name[2]) || ++ '\0' == name[1])) || ++ !((*name >= 'a' && *name <= 'z') || ++ (*name >= 'A' && *name <= 'Z') || ++ (*name >= '0' && *name <= '9') || ++ *name == '_' || ++ *name == '.')) { + return false; + } + ++ numeric = isdigit(*name); ++ + while ('\0' != *++name) { +- if (!(( ('a' <= *name) && ('z' >= *name) ) || +- ( ('0' <= *name) && ('9' >= *name) ) || +- ('_' == *name) || +- ('-' == *name) || +- ( ('$' == *name) && ('\0' == *(name + 1)) ) ++ if (!((*name >= 'a' && *name <= 'z') || ++ (*name >= 'A' && *name <= 'Z') || ++ (*name >= '0' && *name <= '9') || ++ *name == '_' || ++ *name == '.' || ++ *name == '-' || ++ (*name == '$' && name[1] == '\0') + )) { + return false; + } ++ numeric &= isdigit(*name); + } + +- return true; ++ return !numeric; + } + + bool is_valid_user_name (const char *name) +diff -up shadow-4.6/man/groupadd.8.xml.goodname shadow-4.6/man/groupadd.8.xml +--- shadow-4.6/man/groupadd.8.xml.goodname 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/man/groupadd.8.xml 2020-10-23 12:50:47.202529031 +0200 +@@ -273,10 +273,14 @@ + + CAVEATS + +- Groupnames must start with a lower case letter or an underscore, +- followed by lower case letters, digits, underscores, or dashes. +- They can end with a dollar sign. +- In regular expression terms: [a-z_][a-z0-9_-]*[$]? ++ Groupnames may begin with lower and upper case letters, digits, ++ underscores, or periods. They may continue with all the aforementioned ++ characters, or dashes. Finally, they can end with a dollar sign. ++ ++ Fully numeric groupnames and groupnames containing only . or .. are ++ disallowed. ++ ++ In regular expression terms: [a-zA-Z0-9_.][a-zA-Z0-9_.-]*[$]? + + + Groupnames may only be up to &GROUP_NAME_MAX_LENGTH; characters long. +diff -up shadow-4.6/man/useradd.8.xml.goodname shadow-4.6/man/useradd.8.xml +--- shadow-4.6/man/useradd.8.xml.goodname 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/man/useradd.8.xml 2020-10-23 12:50:47.202529031 +0200 +@@ -650,10 +650,16 @@ + + + +- Usernames must start with a lower case letter or an underscore, +- followed by lower case letters, digits, underscores, or dashes. +- They can end with a dollar sign. +- In regular expression terms: [a-z_][a-z0-9_-]*[$]? ++ Usernames may begin with lower and upper case letters, digits, ++ underscores, or periods. They may continue with all the aforementioned ++ characters, or dashes. Finally, they can end with a dollar sign. ++ ++ Fully numeric usernames and usernames containing only . or .. are ++ disallowed. It is not recommended to use usernames beginning ++ with . character as their home directories will be hidden in ++ the ls output. ++ ++ In regular expression terms: [a-zA-Z0-9_.][a-zA-Z0-9_.-]*[$]? + + + Usernames may only be up to 32 characters long. diff --git a/SOURCES/shadow-4.6-gpasswd-fix-password-leak.patch b/SOURCES/shadow-4.6-gpasswd-fix-password-leak.patch new file mode 100644 index 0000000..61bf8c0 --- /dev/null +++ b/SOURCES/shadow-4.6-gpasswd-fix-password-leak.patch @@ -0,0 +1,11 @@ +diff -up shadow-4.9/src/gpasswd.c.gpasswd-fix-password-leak shadow-4.9/src/gpasswd.c +--- shadow-4.9/src/gpasswd.c.gpasswd-fix-password-leak 2023-07-12 09:38:32.062546006 +0200 ++++ shadow-4.9/src/gpasswd.c 2023-07-12 09:42:33.194154548 +0200 +@@ -857,6 +857,7 @@ static void change_passwd (struct group + strzero (cp); + cp = getpass (_("Re-enter new password: ")); + if (NULL == cp) { ++ memzero (pass, sizeof pass); + exit (1); + } + diff --git a/SOURCES/shadow-4.6-groupdel-fix-sigsegv-when-passwd-does-not-exist.patch b/SOURCES/shadow-4.6-groupdel-fix-sigsegv-when-passwd-does-not-exist.patch new file mode 100644 index 0000000..658156a --- /dev/null +++ b/SOURCES/shadow-4.6-groupdel-fix-sigsegv-when-passwd-does-not-exist.patch @@ -0,0 +1,13 @@ +diff -up shadow-4.9/libmisc/prefix_flag.c.groupdel-fix-sigsegv-when-passwd-does-not-exist shadow-4.9/libmisc/prefix_flag.c +--- shadow-4.9/libmisc/prefix_flag.c.groupdel-fix-sigsegv-when-passwd-does-not-exist 2021-11-19 09:21:36.997091941 +0100 ++++ shadow-4.9/libmisc/prefix_flag.c 2021-11-19 09:22:19.001341010 +0100 +@@ -288,6 +288,9 @@ extern struct passwd* prefix_getpwent() + if(!passwd_db_file) { + return getpwent(); + } ++ if (!fp_pwent) { ++ return NULL; ++ } + return fgetpwent(fp_pwent); + } + extern void prefix_endpwent() diff --git a/SOURCES/shadow-4.6-home_mode-directive.patch b/SOURCES/shadow-4.6-home_mode-directive.patch new file mode 100644 index 0000000..f6b50eb --- /dev/null +++ b/SOURCES/shadow-4.6-home_mode-directive.patch @@ -0,0 +1,201 @@ +From a847899b521b0df0665e442845bcff23407d9ea0 Mon Sep 17 00:00:00 2001 +From: Duncan Overbruck +Date: Sat, 11 Jan 2020 22:19:37 +0100 +Subject: [PATCH] add new HOME_MODE login.defs(5) option + +This option can be used to set a separate mode for useradd(8) and +newusers(8) to create the home directories with. +If this option is not set, the current behavior of using UMASK +or the default umask is preserved. + +There are many distributions that set UMASK to 077 by default just +to create home directories not readable by others and use things like +/etc/profile, bashrc or sudo configuration files to set a less +restrictive +umask. This has always resulted in bug reports because it is hard +to follow as users tend to change files like bashrc and are not about +setting the umask to counteract the umask set in /etc/login.defs. + +A recent change in sudo has also resulted in many bug reports about +this. sudo now tries to respect the umask set by pam modules and on +systems where pam does not set a umask, the login.defs UMASK value is +used. +--- + etc/login.defs | 7 ++++++- + lib/getdef.c | 1 + + man/login.defs.5.xml | 4 ++++ + man/login.defs.d/UMASK.xml | 3 ++- + src/newusers.c | 6 +++--- + src/useradd.c | 5 +++-- + 6 files changed, 19 insertions(+), 7 deletions(-) + +diff --git a/etc/login.defs b/etc/login.defs +index cd2597dc..a2f8cd50 100644 +--- a/etc/login.defs ++++ b/etc/login.defs +@@ -195,12 +195,17 @@ KILLCHAR 025 + # Default initial "umask" value used by login(1) on non-PAM enabled systems. + # Default "umask" value for pam_umask(8) on PAM enabled systems. + # UMASK is also used by useradd(8) and newusers(8) to set the mode for new +-# home directories. ++# home directories if HOME_MODE is not set. + # 022 is the default value, but 027, or even 077, could be considered + # for increased privacy. There is no One True Answer here: each sysadmin + # must make up their mind. + UMASK 022 + ++# HOME_MODE is used by useradd(8) and newusers(8) to set the mode for new ++# home directories. ++# If HOME_MODE is not set, the value of UMASK is used to create the mode. ++HOME_MODE 0700 ++ + # + # Password aging controls: + # +diff --git a/lib/getdef.c b/lib/getdef.c +index bbb273f4..00f6abfe 100644 +--- a/lib/getdef.c ++++ b/lib/getdef.c +@@ -93,6 +93,7 @@ static struct itemdef def_table[] = { + {"FAKE_SHELL", NULL}, + {"GID_MAX", NULL}, + {"GID_MIN", NULL}, ++ {"HOME_MODE", NULL}, + {"HUSHLOGIN_FILE", NULL}, + {"KILLCHAR", NULL}, + {"LOGIN_RETRIES", NULL}, +diff --git a/man/login.defs.5.xml b/man/login.defs.5.xml +index ebf60ba3..9e95da20 100644 +--- a/man/login.defs.5.xml ++++ b/man/login.defs.5.xml +@@ -50,6 +50,7 @@ + + + ++ + + + +@@ -185,6 +186,7 @@ + &FAKE_SHELL; + &FTMP_FILE; + &GID_MAX; ++ &HOME_MODE; + &HUSHLOGIN_FILE; + &ISSUE_FILE; + &KILLCHAR; +@@ -401,6 +403,7 @@ + ENCRYPT_METHOD + GID_MAX GID_MIN + MAX_MEMBERS_PER_GROUP MD5_CRYPT_ENAB ++ HOME_MODE + PASS_MAX_DAYS PASS_MIN_DAYS PASS_WARN_AGE + SHA_CRYPT_MAX_ROUNDS + SHA_CRYPT_MIN_ROUNDS +@@ -481,6 +484,7 @@ + + CREATE_HOME + GID_MAX GID_MIN ++ HOME_MODE + MAIL_DIR MAX_MEMBERS_PER_GROUP + PASS_MAX_DAYS PASS_MIN_DAYS PASS_WARN_AGE + SUB_GID_COUNT SUB_GID_MAX SUB_GID_MIN +diff --git a/man/login.defs.d/HOME_MODE.xml b/man/login.defs.d/HOME_MODE.xml +new file mode 100644 +index 00000000..21aa55f7 +--- /dev/null ++++ b/man/login.defs.d/HOME_MODE.xml +@@ -0,0 +1,43 @@ ++ ++ ++ (number) ++ ++ ++ The mode for new home directories. If not specified, ++ the is used to create the mode. ++ ++ ++ useradd and newusers use this ++ to set the mode of the home directory they create. ++ ++ ++ +diff --git a/man/login.defs.d/UMASK.xml b/man/login.defs.d/UMASK.xml +index d7b71a5e..0f061dbb 100644 +--- a/man/login.defs.d/UMASK.xml ++++ b/man/login.defs.d/UMASK.xml +@@ -37,7 +37,8 @@ + + + useradd and newusers use this +- mask to set the mode of the home directory they create ++ mask to set the mode of the home directory they create if ++ is not set. + + + It is also used by login to define users' initial +diff --git a/src/newusers.c b/src/newusers.c +index 99c69f78..e9fe0e27 100644 +--- a/src/newusers.c ++++ b/src/newusers.c +@@ -1216,9 +1216,9 @@ int main (int argc, char **argv) + if ( ('\0' != fields[5][0]) + && (access (newpw.pw_dir, F_OK) != 0)) { + /* FIXME: should check for directory */ +- mode_t msk = 0777 & ~getdef_num ("UMASK", +- GETDEF_DEFAULT_UMASK); +- if (mkdir (newpw.pw_dir, msk) != 0) { ++ mode_t mode = getdef_num ("HOME_MODE", ++ 0777 & ~getdef_num ("UMASK", GETDEF_DEFAULT_UMASK)); ++ if (mkdir (newpw.pw_dir, mode) != 0) { + fprintf (stderr, + _("%s: line %d: mkdir %s failed: %s\n"), + Prog, line, newpw.pw_dir, +diff --git a/src/useradd.c b/src/useradd.c +index 4af0f7c6..8b453e3c 100644 +--- a/src/useradd.c ++++ b/src/useradd.c +@@ -2152,8 +2152,9 @@ static void create_home (void) + fail_exit (E_HOMEDIR); + } + (void) chown (prefix_user_home, user_id, user_gid); +- chmod (prefix_user_home, +- 0777 & ~getdef_num ("UMASK", GETDEF_DEFAULT_UMASK)); ++ mode_t mode = getdef_num ("HOME_MODE", ++ 0777 & ~getdef_num ("UMASK", GETDEF_DEFAULT_UMASK)); ++ chmod (prefix_user_home, mode); + home_added = true; + #ifdef WITH_AUDIT + audit_logger (AUDIT_USER_MGMT, Prog, +-- +2.25.2 + diff --git a/SOURCES/shadow-4.6-ignore-login-prompt.patch b/SOURCES/shadow-4.6-ignore-login-prompt.patch new file mode 100644 index 0000000..faf50f7 --- /dev/null +++ b/SOURCES/shadow-4.6-ignore-login-prompt.patch @@ -0,0 +1,11 @@ +diff -up shadow-4.6/lib/getdef.c.login-prompt shadow-4.6/lib/getdef.c +--- shadow-4.6/lib/getdef.c.login-prompt 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/lib/getdef.c 2019-03-21 15:06:58.009280504 +0100 +@@ -94,6 +94,7 @@ static struct itemdef def_table[] = { + {"KILLCHAR", NULL}, + {"LOGIN_RETRIES", NULL}, + {"LOGIN_TIMEOUT", NULL}, ++ {"LOGIN_PLAIN_PROMPT", NULL}, + {"LOG_OK_LOGINS", NULL}, + {"LOG_UNKFAIL_ENAB", NULL}, + {"MAIL_DIR", NULL}, diff --git a/SOURCES/shadow-4.6-install_subid_h.patch b/SOURCES/shadow-4.6-install_subid_h.patch new file mode 100644 index 0000000..cee2e03 --- /dev/null +++ b/SOURCES/shadow-4.6-install_subid_h.patch @@ -0,0 +1,28 @@ +From 77e39de1e6cbd6925f16bb260abb7d216296886b Mon Sep 17 00:00:00 2001 +From: Serge Hallyn +Date: Tue, 4 May 2021 09:21:11 -0500 +Subject: [PATCH] Install subid.h + +Now subid.h gets installed under /usr/include/shadow/subid.h + +Signed-off-by: Serge Hallyn +--- + libsubid/Makefile.am | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/libsubid/Makefile.am b/libsubid/Makefile.am +index f543b5eb..189165b0 100644 +--- a/libsubid/Makefile.am ++++ b/libsubid/Makefile.am +@@ -3,6 +3,8 @@ libsubid_la_LDFLAGS = -Wl,-soname,libsubid.so.@LIBSUBID_ABI@ \ + -shared -version-info @LIBSUBID_ABI_MAJOR@ + libsubid_la_SOURCES = api.c + ++pkginclude_HEADERS = subid.h ++ + MISCLIBS = \ + $(LIBAUDIT) \ + $(LIBSELINUX) \ +-- +2.31.1 + diff --git a/SOURCES/shadow-4.6-libsubid_creation.patch b/SOURCES/shadow-4.6-libsubid_creation.patch new file mode 100644 index 0000000..bd4b5bc --- /dev/null +++ b/SOURCES/shadow-4.6-libsubid_creation.patch @@ -0,0 +1,1306 @@ +diff -up shadow-4.6/configure.ac.libsubid_creation shadow-4.6/configure.ac +--- shadow-4.6/configure.ac.libsubid_creation 2021-10-19 16:12:02.663748272 +0200 ++++ shadow-4.6/configure.ac 2021-10-19 16:13:07.194697194 +0200 +@@ -1,11 +1,21 @@ + dnl Process this file with autoconf to produce a configure script. +-AC_PREREQ([2.64]) ++AC_PREREQ([2.69]) ++m4_define([libsubid_abi_major], 1) ++m4_define([libsubid_abi_minor], 0) ++m4_define([libsubid_abi_micro], 0) ++m4_define([libsubid_abi], [libsubid_abi_major.libsubid_abi_minor.libsubid_abi_micro]) + AC_INIT([shadow], [4.6], [pkg-shadow-devel@lists.alioth.debian.org], [], + [https://github.com/shadow-maint/shadow]) + AM_INIT_AUTOMAKE([1.11 foreign dist-xz]) ++AC_CONFIG_MACRO_DIRS([m4]) + AM_SILENT_RULES([yes]) + AC_CONFIG_HEADERS([config.h]) + ++AC_SUBST([LIBSUBID_ABI_MAJOR], [libsubid_abi_major]) ++AC_SUBST([LIBSUBID_ABI_MINOR], [libsubid_abi_minor]) ++AC_SUBST([LIBSUBID_ABI_MICRO], [libsubid_abi_micro]) ++AC_SUBST([LIBSUBID_ABI], [libsubid_abi]) ++ + dnl Some hacks... + test "$prefix" = "NONE" && prefix="/usr" + test "$prefix" = "/usr" && exec_prefix="" +@@ -22,8 +22,8 @@ test "$prefix" = "/usr" && exec_prefix="" + + AC_GNU_SOURCE + +-AM_DISABLE_SHARED + AM_ENABLE_STATIC ++AM_ENABLE_SHARED + + AM_MAINTAINER_MODE + +@@ -725,6 +725,7 @@ AC_CONFIG_FILES([ + man/zh_TW/Makefile + libmisc/Makefile + lib/Makefile ++ libsubid/Makefile + src/Makefile + contrib/Makefile + etc/Makefile +diff -up shadow-4.6/libsubid/api.c.libsubid_creation shadow-4.6/libsubid/api.c +--- shadow-4.6/libsubid/api.c.libsubid_creation 2021-10-19 16:12:02.661748243 +0200 ++++ shadow-4.6/libsubid/api.c 2021-10-19 16:12:02.661748243 +0200 +@@ -0,0 +1,231 @@ ++/* ++ * Copyright (c) 2020 Serge Hallyn ++ * All rights reserved. ++ * ++ * 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, this list of conditions and the following disclaimer. ++ * 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 copyright holders or contributors may not be used to ++ * endorse or promote products derived from this software without ++ * specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++ * ``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 COPYRIGHT ++ * HOLDERS OR CONTRIBUTORS 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include "subordinateio.h" ++#include "idmapping.h" ++#include "api.h" ++ ++static struct subordinate_range **get_subid_ranges(const char *owner, enum subid_type id_type) ++{ ++ struct subordinate_range **ranges = NULL; ++ ++ switch (id_type) { ++ case ID_TYPE_UID: ++ if (!sub_uid_open(O_RDONLY)) { ++ return NULL; ++ } ++ break; ++ case ID_TYPE_GID: ++ if (!sub_gid_open(O_RDONLY)) { ++ return NULL; ++ } ++ break; ++ default: ++ return NULL; ++ } ++ ++ ranges = list_owner_ranges(owner, id_type); ++ ++ if (id_type == ID_TYPE_UID) ++ sub_uid_close(); ++ else ++ sub_gid_close(); ++ ++ return ranges; ++} ++ ++struct subordinate_range **get_subuid_ranges(const char *owner) ++{ ++ return get_subid_ranges(owner, ID_TYPE_UID); ++} ++ ++struct subordinate_range **get_subgid_ranges(const char *owner) ++{ ++ return get_subid_ranges(owner, ID_TYPE_GID); ++} ++ ++void subid_free_ranges(struct subordinate_range **ranges) ++{ ++ return free_subordinate_ranges(ranges); ++} ++ ++int get_subid_owner(unsigned long id, uid_t **owner, enum subid_type id_type) ++{ ++ int ret = -1; ++ ++ switch (id_type) { ++ case ID_TYPE_UID: ++ if (!sub_uid_open(O_RDONLY)) { ++ return -1; ++ } ++ break; ++ case ID_TYPE_GID: ++ if (!sub_gid_open(O_RDONLY)) { ++ return -1; ++ } ++ break; ++ default: ++ return -1; ++ } ++ ++ ret = find_subid_owners(id, owner, id_type); ++ ++ if (id_type == ID_TYPE_UID) ++ sub_uid_close(); ++ else ++ sub_gid_close(); ++ ++ return ret; ++} ++ ++int get_subuid_owners(uid_t uid, uid_t **owner) ++{ ++ return get_subid_owner((unsigned long)uid, owner, ID_TYPE_UID); ++} ++ ++int get_subgid_owners(gid_t gid, uid_t **owner) ++{ ++ return get_subid_owner((unsigned long)gid, owner, ID_TYPE_GID); ++} ++ ++bool grant_subid_range(struct subordinate_range *range, bool reuse, ++ enum subid_type id_type) ++{ ++ bool ret; ++ ++ switch (id_type) { ++ case ID_TYPE_UID: ++ if (!sub_uid_lock()) { ++ printf("Failed loging subuids (errno %d)\n", errno); ++ return false; ++ } ++ if (!sub_uid_open(O_CREAT | O_RDWR)) { ++ printf("Failed opening subuids (errno %d)\n", errno); ++ sub_uid_unlock(); ++ return false; ++ } ++ break; ++ case ID_TYPE_GID: ++ if (!sub_gid_lock()) { ++ printf("Failed loging subgids (errno %d)\n", errno); ++ return false; ++ } ++ if (!sub_gid_open(O_CREAT | O_RDWR)) { ++ printf("Failed opening subgids (errno %d)\n", errno); ++ sub_gid_unlock(); ++ return false; ++ } ++ break; ++ default: ++ return false; ++ } ++ ++ ret = new_subid_range(range, id_type, reuse); ++ ++ if (id_type == ID_TYPE_UID) { ++ sub_uid_close(); ++ sub_uid_unlock(); ++ } else { ++ sub_gid_close(); ++ sub_gid_unlock(); ++ } ++ ++ return ret; ++} ++ ++bool grant_subuid_range(struct subordinate_range *range, bool reuse) ++{ ++ return grant_subid_range(range, reuse, ID_TYPE_UID); ++} ++ ++bool grant_subgid_range(struct subordinate_range *range, bool reuse) ++{ ++ return grant_subid_range(range, reuse, ID_TYPE_GID); ++} ++ ++bool free_subid_range(struct subordinate_range *range, enum subid_type id_type) ++{ ++ bool ret; ++ ++ switch (id_type) { ++ case ID_TYPE_UID: ++ if (!sub_uid_lock()) { ++ printf("Failed loging subuids (errno %d)\n", errno); ++ return false; ++ } ++ if (!sub_uid_open(O_CREAT | O_RDWR)) { ++ printf("Failed opening subuids (errno %d)\n", errno); ++ sub_uid_unlock(); ++ return false; ++ } ++ break; ++ case ID_TYPE_GID: ++ if (!sub_gid_lock()) { ++ printf("Failed loging subgids (errno %d)\n", errno); ++ return false; ++ } ++ if (!sub_gid_open(O_CREAT | O_RDWR)) { ++ printf("Failed opening subgids (errno %d)\n", errno); ++ sub_gid_unlock(); ++ return false; ++ } ++ break; ++ default: ++ return false; ++ } ++ ++ ret = release_subid_range(range, id_type); ++ ++ if (id_type == ID_TYPE_UID) { ++ sub_uid_close(); ++ sub_uid_unlock(); ++ } else { ++ sub_gid_close(); ++ sub_gid_unlock(); ++ } ++ ++ return ret; ++} ++ ++bool free_subuid_range(struct subordinate_range *range) ++{ ++ return free_subid_range(range, ID_TYPE_UID); ++} ++ ++bool free_subgid_range(struct subordinate_range *range) ++{ ++ return free_subid_range(range, ID_TYPE_GID); ++} +diff -up shadow-4.6/libsubid/api.h.libsubid_creation shadow-4.6/libsubid/api.h +--- shadow-4.6/libsubid/api.h.libsubid_creation 2021-10-19 16:12:02.661748243 +0200 ++++ shadow-4.6/libsubid/api.h 2021-10-19 16:12:02.662748257 +0200 +@@ -0,0 +1,17 @@ ++#include "subid.h" ++#include ++ ++struct subordinate_range **get_subuid_ranges(const char *owner); ++struct subordinate_range **get_subgid_ranges(const char *owner); ++void subid_free_ranges(struct subordinate_range **ranges); ++ ++int get_subuid_owners(uid_t uid, uid_t **owner); ++int get_subgid_owners(gid_t gid, uid_t **owner); ++ ++/* range should be pre-allocated with owner and count filled in, start is ++ * ignored, can be 0 */ ++bool grant_subuid_range(struct subordinate_range *range, bool reuse); ++bool grant_subgid_range(struct subordinate_range *range, bool reuse); ++ ++bool free_subuid_range(struct subordinate_range *range); ++bool free_subgid_range(struct subordinate_range *range); +diff -up shadow-4.6/libsubid/Makefile.am.libsubid_creation shadow-4.6/libsubid/Makefile.am +--- shadow-4.6/libsubid/Makefile.am.libsubid_creation 2021-10-19 16:12:02.661748243 +0200 ++++ shadow-4.6/libsubid/Makefile.am 2021-10-19 16:12:02.662748257 +0200 +@@ -0,0 +1,24 @@ ++lib_LTLIBRARIES = libsubid.la ++libsubid_la_LDFLAGS = -Wl,-soname,libsubid.so.@LIBSUBID_ABI@ \ ++ -shared -version-info @LIBSUBID_ABI_MAJOR@ ++libsubid_la_SOURCES = api.c ++ ++MISCLIBS = \ ++ $(LIBAUDIT) \ ++ $(LIBSELINUX) \ ++ $(LIBSEMANAGE) \ ++ $(LIBCRYPT_NOPAM) \ ++ $(LIBSKEY) \ ++ $(LIBMD) \ ++ $(LIBCRYPT) \ ++ $(LIBTCB) ++ ++libsubid_la_LIBADD = \ ++ $(top_srcdir)/lib/libshadow.la \ ++ $(MISCLIBS) \ ++ $(top_srcdir)/libmisc/libmisc.a ++ ++AM_CPPFLAGS = \ ++ -I${top_srcdir}/lib \ ++ -I${top_srcdir}/libmisc \ ++ -DLOCALEDIR=\"$(datadir)/locale\" +diff -up shadow-4.6/libsubid/subid.h.libsubid_creation shadow-4.6/libsubid/subid.h +--- shadow-4.6/libsubid/subid.h.libsubid_creation 2021-10-19 16:12:02.661748243 +0200 ++++ shadow-4.6/libsubid/subid.h 2021-10-19 16:12:02.661748243 +0200 +@@ -0,0 +1,17 @@ ++#include ++ ++#ifndef SUBID_RANGE_DEFINED ++#define SUBID_RANGE_DEFINED 1 ++struct subordinate_range { ++ const char *owner; ++ unsigned long start; ++ unsigned long count; ++}; ++ ++enum subid_type { ++ ID_TYPE_UID = 1, ++ ID_TYPE_GID = 2 ++}; ++ ++#define SUBID_NFIELDS 3 ++#endif +diff -up shadow-4.6/lib/subordinateio.c.libsubid_creation shadow-4.6/lib/subordinateio.c +--- shadow-4.6/lib/subordinateio.c.libsubid_creation 2021-10-19 16:12:02.654748139 +0200 ++++ shadow-4.6/lib/subordinateio.c 2021-10-19 16:12:02.661748243 +0200 +@@ -13,14 +13,7 @@ + #include "subordinateio.h" + #include + #include +- +-struct subordinate_range { +- const char *owner; +- unsigned long start; +- unsigned long count; +-}; +- +-#define NFIELDS 3 ++#include + + /* + * subordinate_dup: create a duplicate range +@@ -78,7 +71,7 @@ static void *subordinate_parse (const ch + static char rangebuf[1024]; + int i; + char *cp; +- char *fields[NFIELDS]; ++ char *fields[SUBID_NFIELDS]; + + /* + * Copy the string to a temporary buffer so the substrings can +@@ -93,7 +86,7 @@ static void *subordinate_parse (const ch + * field. The fields are converted into NUL terminated strings. + */ + +- for (cp = rangebuf, i = 0; (i < NFIELDS) && (NULL != cp); i++) { ++ for (cp = rangebuf, i = 0; (i < SUBID_NFIELDS) && (NULL != cp); i++) { + fields[i] = cp; + while (('\0' != *cp) && (':' != *cp)) { + cp++; +@@ -108,10 +101,10 @@ static void *subordinate_parse (const ch + } + + /* +- * There must be exactly NFIELDS colon separated fields or ++ * There must be exactly SUBID_NFIELDS colon separated fields or + * the entry is invalid. Also, fields must be non-blank. + */ +- if (i != NFIELDS || *fields[0] == '\0' || *fields[1] == '\0' || *fields[2] == '\0') ++ if (i != SUBID_NFIELDS || *fields[0] == '\0' || *fields[1] == '\0' || *fields[2] == '\0') + return NULL; + range.owner = fields[0]; + if (getulong (fields[1], &range.start) == 0) +@@ -319,6 +312,39 @@ static bool have_range(struct commonio_d + return false; + } + ++static bool append_range(struct subordinate_range ***ranges, const struct subordinate_range *new, int n) ++{ ++ struct subordinate_range *tmp; ++ if (!*ranges) { ++ *ranges = malloc(2 * sizeof(struct subordinate_range **)); ++ if (!*ranges) ++ return false; ++ } else { ++ struct subordinate_range **new; ++ new = realloc(*ranges, (n + 2) * (sizeof(struct subordinate_range **))); ++ if (!new) ++ return false; ++ *ranges = new; ++ } ++ (*ranges)[n] = (*ranges)[n+1] = NULL; ++ tmp = subordinate_dup(new); ++ if (!tmp) ++ return false; ++ (*ranges)[n] = tmp; ++ return true; ++} ++ ++void free_subordinate_ranges(struct subordinate_range **ranges) ++{ ++ int i; ++ ++ if (!ranges) ++ return; ++ for (i = 0; ranges[i]; i++) ++ subordinate_free(ranges[i]); ++ free(ranges); ++} ++ + /* + * subordinate_range_cmp: compare uid ranges + * +@@ -697,6 +723,160 @@ gid_t sub_gid_find_free_range(gid_t min, + start = find_free_range (&subordinate_gid_db, min, max, count); + return start == ULONG_MAX ? (gid_t) -1 : start; + } ++ ++/* ++ struct subordinate_range **list_owner_ranges(const char *owner, enum subid_type id_type) ++ * ++ * @owner: username ++ * @id_type: UID or GUID ++ * ++ * Returns the subuid or subgid ranges which are owned by the specified ++ * user. Username may be a username or a string representation of a ++ * UID number. If id_type is UID, then subuids are returned, else ++ * subgids are returned. If there is an error, < 0 is returned. ++ * ++ * The caller must free the subordinate range list. ++ */ ++struct subordinate_range **list_owner_ranges(const char *owner, enum subid_type id_type) ++{ ++ // TODO - need to handle owner being either uid or username ++ const struct subordinate_range *range; ++ struct subordinate_range **ranges = NULL; ++ struct commonio_db *db; ++ int size = 0; ++ ++ if (id_type == ID_TYPE_UID) ++ db = &subordinate_uid_db; ++ else ++ db = &subordinate_gid_db; ++ ++ commonio_rewind(db); ++ while ((range = commonio_next(db)) != NULL) { ++ if (0 == strcmp(range->owner, owner)) { ++ if (!append_range(&ranges, range, size++)) { ++ free_subordinate_ranges(ranges); ++ return NULL; ++ } ++ } ++ } ++ ++ return ranges; ++} ++ ++static bool all_digits(const char *str) ++{ ++ int i; ++ ++ for (i = 0; str[i] != '\0'; i++) ++ if (!isdigit(str[i])) ++ return false; ++ return true; ++} ++ ++static int append_uids(uid_t **uids, const char *owner, int n) ++{ ++ uid_t owner_uid; ++ uid_t *ret; ++ int i; ++ ++ if (all_digits(owner)) { ++ i = sscanf(owner, "%d", &owner_uid); ++ if (i != 1) { ++ // should not happen ++ free(*uids); ++ *uids = NULL; ++ return -1; ++ } ++ } else { ++ struct passwd *pwd = getpwnam(owner); ++ if (NULL == pwd) { ++ /* Username not defined in /etc/passwd, or error occured during lookup */ ++ free(*uids); ++ *uids = NULL; ++ return -1; ++ } ++ owner_uid = pwd->pw_uid; ++ } ++ ++ for (i = 0; i < n; i++) { ++ if (owner_uid == (*uids)[i]) ++ return n; ++ } ++ ++ ret = realloc(*uids, (n + 1) * sizeof(uid_t)); ++ if (!ret) { ++ free(*uids); ++ return -1; ++ } ++ ret[n] = owner_uid; ++ *uids = ret; ++ return n+1; ++} ++ ++int find_subid_owners(unsigned long id, uid_t **uids, enum subid_type id_type) ++{ ++ const struct subordinate_range *range; ++ struct commonio_db *db; ++ int n = 0; ++ ++ *uids = NULL; ++ if (id_type == ID_TYPE_UID) ++ db = &subordinate_uid_db; ++ else ++ db = &subordinate_gid_db; ++ ++ commonio_rewind(db); ++ while ((range = commonio_next(db)) != NULL) { ++ if (id >= range->start && id < range->start + range-> count) { ++ n = append_uids(uids, range->owner, n); ++ if (n < 0) ++ break; ++ } ++ } ++ ++ return n; ++} ++ ++bool new_subid_range(struct subordinate_range *range, enum subid_type id_type, bool reuse) ++{ ++ struct commonio_db *db; ++ const struct subordinate_range *r; ++ ++ if (id_type == ID_TYPE_UID) ++ db = &subordinate_uid_db; ++ else ++ db = &subordinate_gid_db; ++ commonio_rewind(db); ++ if (reuse) { ++ while ((r = commonio_next(db)) != NULL) { ++ // TODO account for username vs uid_t ++ if (0 != strcmp(r->owner, range->owner)) ++ continue; ++ if (r->count >= range->count) { ++ range->count = r->count; ++ range->start = r->start; ++ return true; ++ } ++ } ++ } ++ ++ range->start = find_free_range(db, range->start, ULONG_MAX, range->count); ++ if (range->start == ULONG_MAX) ++ return false; ++ ++ return add_range(db, range->owner, range->start, range->count) == 1; ++} ++ ++bool release_subid_range(struct subordinate_range *range, enum subid_type id_type) ++{ ++ struct commonio_db *db; ++ if (id_type == ID_TYPE_UID) ++ db = &subordinate_uid_db; ++ else ++ db = &subordinate_gid_db; ++ return remove_range(db, range->owner, range->start, range->count) == 1; ++} ++ + #else /* !ENABLE_SUBIDS */ + extern int errno; /* warning: ANSI C forbids an empty source file */ + #endif /* !ENABLE_SUBIDS */ +diff -up shadow-4.6/lib/subordinateio.h.libsubid_creation shadow-4.6/lib/subordinateio.h +--- shadow-4.6/lib/subordinateio.h.libsubid_creation 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/lib/subordinateio.h 2021-10-19 16:12:02.661748243 +0200 +@@ -11,6 +11,8 @@ + + #include + ++#include "../libsubid/subid.h" ++ + extern int sub_uid_close(void); + extern bool have_sub_uids(const char *owner, uid_t start, unsigned long count); + extern bool sub_uid_file_present (void); +@@ -23,6 +25,11 @@ extern int sub_uid_unlock (void); + extern int sub_uid_add (const char *owner, uid_t start, unsigned long count); + extern int sub_uid_remove (const char *owner, uid_t start, unsigned long count); + extern uid_t sub_uid_find_free_range(uid_t min, uid_t max, unsigned long count); ++extern struct subordinate_range **list_owner_ranges(const char *owner, enum subid_type id_type); ++extern bool new_subid_range(struct subordinate_range *range, enum subid_type id_type, bool reuse); ++extern bool release_subid_range(struct subordinate_range *range, enum subid_type id_type); ++extern int find_subid_owners(unsigned long id, uid_t **uids, enum subid_type id_type); ++extern void free_subordinate_ranges(struct subordinate_range **ranges); + + extern int sub_gid_close(void); + extern bool have_sub_gids(const char *owner, gid_t start, unsigned long count); +diff -up shadow-4.6/Makefile.am.libsubid_creation shadow-4.6/Makefile.am +--- shadow-4.6/Makefile.am.libsubid_creation 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/Makefile.am 2021-10-19 16:12:02.660748228 +0200 +@@ -2,5 +2,14 @@ + + EXTRA_DIST = NEWS README TODO shadow.spec.in + +-SUBDIRS = po man libmisc lib src \ +- contrib doc etc ++SUBDIRS = libmisc lib ++ ++if ENABLE_SUBIDS ++SUBDIRS += libsubid ++endif ++ ++SUBDIRS += src po contrib doc etc ++ ++if ENABLE_REGENERATE_MAN ++SUBDIRS += man ++endif +diff -up shadow-4.6/src/free_subid_range.c.libsubid_creation shadow-4.6/src/free_subid_range.c +--- shadow-4.6/src/free_subid_range.c.libsubid_creation 2021-10-19 16:12:02.661748243 +0200 ++++ shadow-4.6/src/free_subid_range.c 2021-10-19 16:12:02.661748243 +0200 +@@ -0,0 +1,50 @@ ++#include ++#include ++#include "api.h" ++#include "stdlib.h" ++#include "prototypes.h" ++ ++/* Test program for the subid freeing routine */ ++ ++const char *Prog; ++ ++void usage(void) ++{ ++ fprintf(stderr, "Usage: %s [-g] user start count\n", Prog); ++ fprintf(stderr, " Release a user's subuid (or with -g, subgid) range\n"); ++ exit(EXIT_FAILURE); ++} ++ ++int main(int argc, char *argv[]) ++{ ++ int c; ++ bool ok; ++ struct subordinate_range range; ++ bool group = false; // get subuids by default ++ ++ Prog = Basename (argv[0]); ++ while ((c = getopt(argc, argv, "g")) != EOF) { ++ switch(c) { ++ case 'g': group = true; break; ++ default: usage(); ++ } ++ } ++ argv = &argv[optind]; ++ argc = argc - optind; ++ if (argc < 3) ++ usage(); ++ range.owner = argv[0]; ++ range.start = atoi(argv[1]); ++ range.count = atoi(argv[2]); ++ if (group) ++ ok = free_subgid_range(&range); ++ else ++ ok = free_subuid_range(&range); ++ ++ if (!ok) { ++ fprintf(stderr, "Failed freeing id range\n"); ++ exit(EXIT_FAILURE); ++ } ++ ++ return 0; ++} +diff -up shadow-4.6/src/get_subid_owners.c.libsubid_creation shadow-4.6/src/get_subid_owners.c +--- shadow-4.6/src/get_subid_owners.c.libsubid_creation 2021-10-19 16:12:02.661748243 +0200 ++++ shadow-4.6/src/get_subid_owners.c 2021-10-19 16:12:02.661748243 +0200 +@@ -0,0 +1,40 @@ ++#include ++#include "api.h" ++#include "stdlib.h" ++#include "prototypes.h" ++ ++const char *Prog; ++ ++void usage(void) ++{ ++ fprintf(stderr, "Usage: [-g] %s subuid\n", Prog); ++ fprintf(stderr, " list uids who own the given subuid\n"); ++ fprintf(stderr, " pass -g to query a subgid\n"); ++ exit(EXIT_FAILURE); ++} ++ ++int main(int argc, char *argv[]) ++{ ++ int i, n; ++ uid_t *uids; ++ ++ Prog = Basename (argv[0]); ++ if (argc < 2) { ++ usage(); ++ } ++ if (argc == 3 && strcmp(argv[1], "-g") == 0) ++ n = get_subgid_owners(atoi(argv[2]), &uids); ++ else if (argc == 2 && strcmp(argv[1], "-h") == 0) ++ usage(); ++ else ++ n = get_subuid_owners(atoi(argv[1]), &uids); ++ if (n < 0) { ++ fprintf(stderr, "No owners found\n"); ++ exit(1); ++ } ++ for (i = 0; i < n; i++) { ++ printf("%d\n", uids[i]); ++ } ++ free(uids); ++ return 0; ++} +diff -up shadow-4.6/src/list_subid_ranges.c.libsubid_creation shadow-4.6/src/list_subid_ranges.c +--- shadow-4.6/src/list_subid_ranges.c.libsubid_creation 2021-10-19 16:12:02.661748243 +0200 ++++ shadow-4.6/src/list_subid_ranges.c 2021-10-19 16:12:02.661748243 +0200 +@@ -0,0 +1,41 @@ ++#include ++#include "api.h" ++#include "stdlib.h" ++#include "prototypes.h" ++ ++const char *Prog; ++ ++void usage(void) ++{ ++ fprintf(stderr, "Usage: %s [-g] user\n", Prog); ++ fprintf(stderr, " list subuid ranges for user\n"); ++ fprintf(stderr, " pass -g to list subgid ranges\n"); ++ exit(EXIT_FAILURE); ++} ++ ++int main(int argc, char *argv[]) ++{ ++ int i; ++ struct subordinate_range **ranges; ++ ++ Prog = Basename (argv[0]); ++ if (argc < 2) { ++ usage(); ++ } ++ if (argc == 3 && strcmp(argv[1], "-g") == 0) ++ ranges = get_subgid_ranges(argv[2]); ++ else if (argc == 2 && strcmp(argv[1], "-h") == 0) ++ usage(); ++ else ++ ranges = get_subuid_ranges(argv[1]); ++ if (!ranges) { ++ fprintf(stderr, "Error fetching ranges\n"); ++ exit(1); ++ } ++ for (i = 0; ranges[i]; i++) { ++ printf("%d: %s %lu %lu\n", i, ranges[i]->owner, ++ ranges[i]->start, ranges[i]->count); ++ } ++ subid_free_ranges(ranges); ++ return 0; ++} +diff -up shadow-4.6/src/new_subid_range.c.libsubid_creation shadow-4.6/src/new_subid_range.c +--- shadow-4.6/src/new_subid_range.c.libsubid_creation 2021-10-19 16:12:02.661748243 +0200 ++++ shadow-4.6/src/new_subid_range.c 2021-10-19 16:12:02.661748243 +0200 +@@ -0,0 +1,57 @@ ++#include ++#include ++#include "api.h" ++#include "stdlib.h" ++#include "prototypes.h" ++ ++/* Test program for the subid creation routine */ ++ ++const char *Prog; ++ ++void usage(void) ++{ ++ fprintf(stderr, "Usage: %s [-g] [-n] user count\n", Prog); ++ fprintf(stderr, " Find a subuid (or with -g, subgid) range for user\n"); ++ fprintf(stderr, " If -n is given, a new range will be created even if one exists\n"); ++ fprintf(stderr, " count defaults to 65536\n"); ++ exit(EXIT_FAILURE); ++} ++ ++int main(int argc, char *argv[]) ++{ ++ int c; ++ struct subordinate_range range; ++ bool makenew = false; // reuse existing by default ++ bool group = false; // get subuids by default ++ bool ok; ++ ++ Prog = Basename (argv[0]); ++ while ((c = getopt(argc, argv, "gn")) != EOF) { ++ switch(c) { ++ case 'n': makenew = true; break; ++ case 'g': group = true; break; ++ default: usage(); ++ } ++ } ++ argv = &argv[optind]; ++ argc = argc - optind; ++ if (argc == 0) ++ usage(); ++ range.owner = argv[0]; ++ range.start = 0; ++ range.count = 65536; ++ if (argc > 1) ++ range.count = atoi(argv[1]); ++ if (group) ++ ok = grant_subgid_range(&range, !makenew); ++ else ++ ok = grant_subuid_range(&range, !makenew); ++ ++ if (!ok) { ++ fprintf(stderr, "Failed creating new id range\n"); ++ exit(EXIT_FAILURE); ++ } ++ printf("Subuid range %lu:%lu\n", range.start, range.count); ++ ++ return 0; ++} +diff -up shadow-4.6/tests/libsubid/01_list_ranges/config/etc/subgid.libsubid_creation shadow-4.6/tests/libsubid/01_list_ranges/config/etc/subgid +--- shadow-4.6/tests/libsubid/01_list_ranges/config/etc/subgid.libsubid_creation 2021-10-19 16:12:02.662748257 +0200 ++++ shadow-4.6/tests/libsubid/01_list_ranges/config/etc/subgid 2021-10-19 16:12:02.662748257 +0200 +@@ -0,0 +1,2 @@ ++foo:200000:10000 ++root:500000:1000 +diff -up shadow-4.6/tests/libsubid/01_list_ranges/config/etc/subuid.libsubid_creation shadow-4.6/tests/libsubid/01_list_ranges/config/etc/subuid +--- shadow-4.6/tests/libsubid/01_list_ranges/config/etc/subuid.libsubid_creation 2021-10-19 16:12:02.662748257 +0200 ++++ shadow-4.6/tests/libsubid/01_list_ranges/config/etc/subuid 2021-10-19 16:12:02.662748257 +0200 +@@ -0,0 +1,3 @@ ++foo:300000:10000 ++foo:400000:10000 ++root:500000:1000 +diff -up shadow-4.6/tests/libsubid/01_list_ranges/config.txt.libsubid_creation shadow-4.6/tests/libsubid/01_list_ranges/config.txt +diff -up shadow-4.6/tests/libsubid/01_list_ranges/list_ranges.test.libsubid_creation shadow-4.6/tests/libsubid/01_list_ranges/list_ranges.test +--- shadow-4.6/tests/libsubid/01_list_ranges/list_ranges.test.libsubid_creation 2021-10-19 16:12:02.662748257 +0200 ++++ shadow-4.6/tests/libsubid/01_list_ranges/list_ranges.test 2021-10-19 16:12:02.662748257 +0200 +@@ -0,0 +1,38 @@ ++#!/bin/sh ++ ++set -e ++ ++cd $(dirname $0) ++ ++. ../../common/config.sh ++. ../../common/log.sh ++ ++log_start "$0" "list_ranges shows subid ranges" ++ ++save_config ++ ++# restore the files on exit ++trap 'log_status "$0" "FAILURE"; restore_config' 0 ++ ++change_config ++ ++echo -n "list foo's ranges..." ++${build_path}/src/list_subid_ranges foo > /tmp/subuidlistout ++${build_path}/src/list_subid_ranges -g foo > /tmp/subgidlistout ++echo "OK" ++ ++echo -n "Check the subuid ranges..." ++[ $(wc -l /tmp/subuidlistout | awk '{ print $1 }') -eq 2 ] ++grep "0: foo 300000 10000" /tmp/subuidlistout ++grep "1: foo 400000 10000" /tmp/subuidlistout ++echo "OK" ++ ++echo -n "Check the subgid ranges..." ++[ $(wc -l /tmp/subgidlistout | awk '{ print $1 }') -eq 1 ] ++grep "0: foo 200000 10000" /tmp/subgidlistout ++echo "OK" ++ ++log_status "$0" "SUCCESS" ++restore_config ++trap '' 0 ++ +diff -up shadow-4.6/tests/libsubid/02_get_subid_owners/config/etc/passwd.libsubid_creation shadow-4.6/tests/libsubid/02_get_subid_owners/config/etc/passwd +--- shadow-4.6/tests/libsubid/02_get_subid_owners/config/etc/passwd.libsubid_creation 2021-10-19 16:12:02.662748257 +0200 ++++ shadow-4.6/tests/libsubid/02_get_subid_owners/config/etc/passwd 2021-10-19 16:12:02.662748257 +0200 +@@ -0,0 +1,20 @@ ++root:x:0:0:root:/root:/bin/bash ++daemon:x:1:1:daemon:/usr/sbin:/bin/sh ++bin:x:2:2:bin:/bin:/bin/sh ++sys:x:3:3:sys:/dev:/bin/sh ++sync:x:4:65534:sync:/bin:/bin/sync ++games:x:5:60:games:/usr/games:/bin/sh ++man:x:6:12:man:/var/cache/man:/bin/sh ++lp:x:7:7:lp:/var/spool/lpd:/bin/sh ++mail:x:8:8:mail:/var/mail:/bin/sh ++news:x:9:9:news:/var/spool/news:/bin/sh ++uucp:x:10:10:uucp:/var/spool/uucp:/bin/sh ++proxy:x:13:13:proxy:/bin:/bin/sh ++www-data:x:33:33:www-data:/var/www:/bin/sh ++backup:x:34:34:backup:/var/backups:/bin/sh ++list:x:38:38:Mailing List Manager:/var/list:/bin/sh ++irc:x:39:39:ircd:/var/run/ircd:/bin/sh ++gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/bin/sh ++nobody:x:65534:65534:nobody:/nonexistent:/bin/sh ++Debian-exim:x:102:102::/var/spool/exim4:/bin/false ++foo:x:1000:1000::/home/foo:/bin/false +diff -up shadow-4.6/tests/libsubid/02_get_subid_owners/config/etc/subgid.libsubid_creation shadow-4.6/tests/libsubid/02_get_subid_owners/config/etc/subgid +--- shadow-4.6/tests/libsubid/02_get_subid_owners/config/etc/subgid.libsubid_creation 2021-10-19 16:12:02.662748257 +0200 ++++ shadow-4.6/tests/libsubid/02_get_subid_owners/config/etc/subgid 2021-10-19 16:12:02.662748257 +0200 +@@ -0,0 +1,2 @@ ++foo:200000:10000 ++root:500000:1000 +diff -up shadow-4.6/tests/libsubid/02_get_subid_owners/config/etc/subuid.libsubid_creation shadow-4.6/tests/libsubid/02_get_subid_owners/config/etc/subuid +--- shadow-4.6/tests/libsubid/02_get_subid_owners/config/etc/subuid.libsubid_creation 2021-10-19 16:12:02.662748257 +0200 ++++ shadow-4.6/tests/libsubid/02_get_subid_owners/config/etc/subuid 2021-10-19 16:12:02.662748257 +0200 +@@ -0,0 +1,4 @@ ++foo:300000:10000 ++foo:400000:10000 ++foo:500000:10000 ++root:500000:1000 +diff -up shadow-4.6/tests/libsubid/02_get_subid_owners/config.txt.libsubid_creation shadow-4.6/tests/libsubid/02_get_subid_owners/config.txt +diff -up shadow-4.6/tests/libsubid/02_get_subid_owners/get_subid_owners.test.libsubid_creation shadow-4.6/tests/libsubid/02_get_subid_owners/get_subid_owners.test +--- shadow-4.6/tests/libsubid/02_get_subid_owners/get_subid_owners.test.libsubid_creation 2021-10-19 16:12:02.662748257 +0200 ++++ shadow-4.6/tests/libsubid/02_get_subid_owners/get_subid_owners.test 2021-10-19 16:12:02.662748257 +0200 +@@ -0,0 +1,52 @@ ++#!/bin/sh ++ ++set -e ++ ++cd $(dirname $0) ++ ++. ../../common/config.sh ++. ../../common/log.sh ++ ++log_start "$0" "get subid owners" ++ ++save_config ++ ++# restore the files on exit ++trap 'log_status "$0" "FAILURE"; restore_config' 0 ++ ++change_config ++ ++echo -n "Noone owns 0 as a subid..." ++[ -z "$(${build_path}/src/get_subid_owners 0)" ] ++echo "OK" ++ ++echo -n "foo owns subuid 300000..." ++[ "$(${build_path}/src/get_subid_owners 300000)" = "1000" ] ++echo "OK" ++ ++echo -n "foo owns subgid 200000..." ++[ "$(${build_path}/src/get_subid_owners -g 200000)" = "1000" ] ++echo "OK" ++ ++echo -n "Noone owns subuid 200000..." ++[ -z "$(${build_path}/src/get_subid_owners -g 300000)" ] ++echo "OK" ++ ++echo -n "Noone owns subgid 300000..." ++[ -z "$(${build_path}/src/get_subid_owners -g 300000)" ] ++echo "OK" ++ ++echo -n "Both foo and root own subuid 500000..." ++cat > /tmp/expected << EOF ++1000 ++0 ++EOF ++${build_path}/src/get_subid_owners 500000 > /tmp/actual ++diff /tmp/expected /tmp/actual ++ ++echo "OK" ++ ++log_status "$0" "SUCCESS" ++restore_config ++trap '' 0 ++ +diff -up shadow-4.6/tests/libsubid/03_add_remove/add_remove_subids.test.libsubid_creation shadow-4.6/tests/libsubid/03_add_remove/add_remove_subids.test +--- shadow-4.6/tests/libsubid/03_add_remove/add_remove_subids.test.libsubid_creation 2021-10-19 16:12:02.662748257 +0200 ++++ shadow-4.6/tests/libsubid/03_add_remove/add_remove_subids.test 2021-10-19 16:12:02.662748257 +0200 +@@ -0,0 +1,59 @@ ++#!/bin/sh ++ ++set -e ++ ++cd $(dirname $0) ++ ++. ../../common/config.sh ++. ../../common/log.sh ++ ++log_start "$0" "add and remove subid ranges" ++ ++save_config ++ ++# restore the files on exit ++trap 'log_status "$0" "FAILURE"; restore_config' 0 ++ ++change_config ++ ++echo -n "Existing ranges returned when possible..." ++res=$(${build_path}/src/new_subid_range foo 500) ++echo "debug" ++echo "res is $res" ++echo "wanted Subuid range 300000:10000" ++echo "end debug" ++[ "$res" = "Subuid range 300000:10000" ] ++[ $(grep -c foo /etc/subuid) -eq 1 ] ++echo "OK" ++ ++echo -n "New range returned if requested..." ++res=$(${build_path}/src/new_subid_range foo 500 -n) ++[ "$res" = "Subuid range 310000:500" ] ++[ $(grep -c foo /etc/subuid) -eq 2 ] ++echo "OK" ++ ++echo -n "Free works..." ++res=$(${build_path}/src/free_subid_range foo 310000 500) ++[ $(grep -c foo /etc/subuid) -eq 1 ] ++echo "OK" ++ ++echo -n "Subgids work too..." ++res=$(${build_path}/src/new_subid_range -g foo 100000) ++echo "DEBUG: res is ${res}" ++[ "$res" = "Subuid range 501000:100000" ] ++echo "DEBUG: subgid is:" ++cat /etc/subgid ++[ $(grep -c foo /etc/subgid) -eq 2 ] ++ ++echo -n "Subgid free works..." ++res=$(${build_path}/src/free_subid_range -g foo 501000 100000) ++echo "DEBUG: res is ${res}" ++echo "DEBUG: subgid is:" ++cat /etc/subgid ++[ $(grep -c foo /etc/subgid) -eq 1 ] ++echo "OK" ++ ++log_status "$0" "SUCCESS" ++restore_config ++trap '' 0 ++ +diff -up shadow-4.6/tests/libsubid/03_add_remove/config/etc/passwd.libsubid_creation shadow-4.6/tests/libsubid/03_add_remove/config/etc/passwd +--- shadow-4.6/tests/libsubid/03_add_remove/config/etc/passwd.libsubid_creation 2021-10-19 16:12:02.662748257 +0200 ++++ shadow-4.6/tests/libsubid/03_add_remove/config/etc/passwd 2021-10-19 16:12:02.662748257 +0200 +@@ -0,0 +1,20 @@ ++root:x:0:0:root:/root:/bin/bash ++daemon:x:1:1:daemon:/usr/sbin:/bin/sh ++bin:x:2:2:bin:/bin:/bin/sh ++sys:x:3:3:sys:/dev:/bin/sh ++sync:x:4:65534:sync:/bin:/bin/sync ++games:x:5:60:games:/usr/games:/bin/sh ++man:x:6:12:man:/var/cache/man:/bin/sh ++lp:x:7:7:lp:/var/spool/lpd:/bin/sh ++mail:x:8:8:mail:/var/mail:/bin/sh ++news:x:9:9:news:/var/spool/news:/bin/sh ++uucp:x:10:10:uucp:/var/spool/uucp:/bin/sh ++proxy:x:13:13:proxy:/bin:/bin/sh ++www-data:x:33:33:www-data:/var/www:/bin/sh ++backup:x:34:34:backup:/var/backups:/bin/sh ++list:x:38:38:Mailing List Manager:/var/list:/bin/sh ++irc:x:39:39:ircd:/var/run/ircd:/bin/sh ++gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/bin/sh ++nobody:x:65534:65534:nobody:/nonexistent:/bin/sh ++Debian-exim:x:102:102::/var/spool/exim4:/bin/false ++foo:x:1000:1000::/home/foo:/bin/false +diff -up shadow-4.6/tests/libsubid/03_add_remove/config/etc/subgid.libsubid_creation shadow-4.6/tests/libsubid/03_add_remove/config/etc/subgid +--- shadow-4.6/tests/libsubid/03_add_remove/config/etc/subgid.libsubid_creation 2021-10-19 16:12:02.662748257 +0200 ++++ shadow-4.6/tests/libsubid/03_add_remove/config/etc/subgid 2021-10-19 16:12:02.662748257 +0200 +@@ -0,0 +1,2 @@ ++foo:200000:10000 ++root:500000:1000 +diff -up shadow-4.6/tests/libsubid/03_add_remove/config/etc/subuid.libsubid_creation shadow-4.6/tests/libsubid/03_add_remove/config/etc/subuid +--- shadow-4.6/tests/libsubid/03_add_remove/config/etc/subuid.libsubid_creation 2021-10-19 16:12:02.662748257 +0200 ++++ shadow-4.6/tests/libsubid/03_add_remove/config/etc/subuid 2021-10-19 16:12:02.662748257 +0200 +@@ -0,0 +1 @@ ++foo:300000:10000 +diff -up shadow-4.6/tests/libsubid/03_add_remove/config.txt.libsubid_creation shadow-4.6/tests/libsubid/03_add_remove/config.txt +diff -up shadow-4.6/tests/run_some.libsubid_creation shadow-4.6/tests/run_some +--- shadow-4.6/tests/run_some.libsubid_creation 2021-10-19 16:12:02.662748257 +0200 ++++ shadow-4.6/tests/run_some 2021-10-19 16:12:02.662748257 +0200 +@@ -0,0 +1,136 @@ ++#!/bin/sh ++ ++set -e ++ ++export LC_ALL=C ++unset LANG ++unset LANGUAGE ++. common/config.sh ++ ++USE_PAM="yes" ++FAILURE_TESTS="yes" ++ ++succeeded=0 ++failed=0 ++failed_tests="" ++ ++run_test() ++{ ++ [ -f RUN_TEST.STOP ] && exit 1 ++ ++ if $1 > $1.log ++ then ++ succeeded=$((succeeded+1)) ++ echo -n "+" ++ else ++ failed=$((failed+1)) ++ failed_tests="$failed_tests $1" ++ echo -n "-" ++ fi ++ cat $1.log >> testsuite.log ++ [ -f /etc/passwd.lock ] && echo $1 /etc/passwd.lock || true ++ [ -f /etc/group.lock ] && echo $1 /etc/group.lock || true ++ [ -f /etc/shadow.lock ] && echo $1 /etc/shadow.lock || true ++ [ -f /etc/gshadow.lock ] && echo $1 /etc/gshadow.lock || true ++ if [ "$(stat -c"%G" /etc/shadow)" != "shadow" ] ++ then ++ echo $1 ++ ls -l /etc/shadow ++ chgrp shadow /etc/shadow ++ fi ++ if [ -d /nonexistent ] ++ then ++ echo $1 /nonexistent ++ rmdir /nonexistent ++ fi ++} ++ ++echo "+: test passed" ++echo "-: test failed" ++ ++# Empty the complete log. ++> testsuite.log ++ ++find ${build_path} -name "*.gcda" -delete ++run_test ./su/01/su_root.test ++run_test ./su/01/su_user.test ++find ${build_path} -name "*.gcda" -exec chmod a+rw {} \; ++run_test ./su/02/env_FOO-options_--login ++run_test ./su/02/env_FOO-options_--login_bash ++run_test ./su/02/env_FOO-options_--preserve-environment ++run_test ./su/02/env_FOO-options_--preserve-environment_bash ++run_test ./su/02/env_FOO-options_- ++run_test ./su/02/env_FOO-options_-_bash ++run_test ./su/02/env_FOO-options_-l-m ++run_test ./su/02/env_FOO-options_-l-m_bash ++run_test ./su/02/env_FOO-options_-l ++run_test ./su/02/env_FOO-options_-l_bash ++run_test ./su/02/env_FOO-options_-m_bash ++run_test ./su/02/env_FOO-options_-m ++run_test ./su/02/env_FOO-options_-p ++run_test ./su/02/env_FOO-options_-p_bash ++run_test ./su/02/env_FOO-options__bash ++run_test ./su/02/env_FOO-options_ ++run_test ./su/02/env_FOO-options_-p- ++run_test ./su/02/env_FOO-options_-p-_bash ++run_test ./su/02/env_special-options_-l-p ++run_test ./su/02/env_special-options_-l ++run_test ./su/02/env_special-options_-l-p_bash ++run_test ./su/02/env_special-options_-l_bash ++run_test ./su/02/env_special-options_-p ++run_test ./su/02/env_special-options_-p_bash ++run_test ./su/02/env_special-options_ ++run_test ./su/02/env_special-options__bash ++run_test ./su/02/env_special_root-options_-l-p ++run_test ./su/02/env_special_root-options_-l-p_bash ++run_test ./su/02/env_special_root-options_-l ++run_test ./su/02/env_special_root-options_-l_bash ++run_test ./su/02/env_special_root-options_-p ++run_test ./su/02/env_special_root-options_-p_bash ++run_test ./su/02/env_special_root-options_ ++run_test ./su/02/env_special_root-options__bash ++run_test ./su/03/su_run_command01.test ++run_test ./su/03/su_run_command02.test ++run_test ./su/03/su_run_command03.test ++run_test ./su/03/su_run_command04.test ++run_test ./su/03/su_run_command05.test ++run_test ./su/03/su_run_command06.test ++run_test ./su/03/su_run_command07.test ++run_test ./su/03/su_run_command08.test ++run_test ./su/03/su_run_command09.test ++run_test ./su/03/su_run_command10.test ++run_test ./su/03/su_run_command11.test ++run_test ./su/03/su_run_command12.test ++run_test ./su/03/su_run_command13.test ++run_test ./su/03/su_run_command14.test ++run_test ./su/03/su_run_command15.test ++run_test ./su/03/su_run_command16.test ++run_test ./su/03/su_run_command17.test ++run_test ./su/04/su_wrong_user.test ++run_test ./su/04/su_user_wrong_passwd.test ++run_test ./su/04/su_user_wrong_passwd_syslog.test ++run_test ./su/05/su_user_wrong_passwd_syslog.test ++run_test ./su/06/su_user_syslog.test ++run_test ./su/07/su_user_syslog.test ++run_test ./su/08/env_special-options_ ++run_test ./su/08/env_special_root-options_ ++run_test ./su/09/env_special-options_ ++run_test ./su/09/env_special_root-options_ ++run_test ./su/10_su_sulog_success/su.test ++run_test ./su/11_su_sulog_failure/su.test ++run_test ./su/12_su_child_failure/su.test ++run_test ./su/13_su_child_success/su.test ++run_test ./libsubid/01_list_ranges/list_ranges.test ++run_test ./libsubid/02_get_subid_owners/get_subid_owners.test ++run_test ./libsubid/03_add_remove/add_remove_subids.test ++ ++echo ++echo "$succeeded test(s) passed" ++echo "$failed test(s) failed" ++echo "log written in 'testsuite.log'" ++if [ "$failed" != "0" ] ++then ++ echo "the following tests failed:" ++ echo $failed_tests ++fi ++ +diff -up shadow-4.6/src/Makefile.am.libsubid_creation shadow-4.6/src/Makefile.am +--- shadow-4.6/src/Makefile.am.bp 2021-10-19 13:13:14.132503541 +0200 ++++ shadow-4.6/src/Makefile.am 2021-10-19 13:14:40.055871030 +0200 +@@ -138,3 +138,64 @@ + chmod $(sgidperms) $(DESTDIR)$(ubindir)/$$i; \ + done + endif ++ ++if ENABLE_SUBIDS ++noinst_PROGRAMS += list_subid_ranges \ ++ get_subid_owners \ ++ new_subid_range \ ++ free_subid_range ++ ++MISCLIBS = \ ++ $(LIBAUDIT) \ ++ $(LIBSELINUX) \ ++ $(LIBSEMANAGE) \ ++ $(LIBCRYPT_NOPAM) \ ++ $(LIBSKEY) \ ++ $(LIBMD) \ ++ $(LIBCRYPT) \ ++ $(LIBTCB) ++ ++list_subid_ranges_LDADD = \ ++ $(top_builddir)/lib/libshadow.la \ ++ $(top_builddir)/libmisc/libmisc.a \ ++ $(top_builddir)/libsubid/libsubid.la \ ++ $(MISCLIBS) ++ ++list_subid_ranges_CPPFLAGS = \ ++ -I$(top_srcdir)/lib \ ++ -I$(top_srcdir)/libmisc \ ++ -I$(top_srcdir)/libsubid ++ ++get_subid_owners_LDADD = \ ++ $(top_builddir)/lib/libshadow.la \ ++ $(top_builddir)/libmisc/libmisc.a \ ++ $(top_builddir)/libsubid/libsubid.la \ ++ $(MISCLIBS) ++ ++get_subid_owners_CPPFLAGS = \ ++ -I$(top_srcdir)/lib \ ++ -I$(top_srcdir)/libmisc \ ++ -I$(top_srcdir)/libsubid ++ ++new_subid_range_CPPFLAGS = \ ++ -I$(top_srcdir)/lib \ ++ -I$(top_srcdir)/libmisc \ ++ -I$(top_srcdir)/libsubid ++ ++new_subid_range_LDADD = \ ++ $(top_builddir)/lib/libshadow.la \ ++ $(top_builddir)/libmisc/libmisc.a \ ++ $(top_builddir)/libsubid/libsubid.la \ ++ $(MISCLIBS) ++ ++free_subid_range_CPPFLAGS = \ ++ -I$(top_srcdir)/lib \ ++ -I$(top_srcdir)/libmisc \ ++ -I$(top_srcdir)/libsubid ++ ++free_subid_range_LDADD = \ ++ $(top_builddir)/lib/libshadow.la \ ++ $(top_builddir)/libmisc/libmisc.a \ ++ $(top_builddir)/libsubid/libsubid.la \ ++ $(MISCLIBS) ++endif diff --git a/SOURCES/shadow-4.6-libsubid_fix_newusers_nss_provides_subids.patch b/SOURCES/shadow-4.6-libsubid_fix_newusers_nss_provides_subids.patch new file mode 100644 index 0000000..c0ca905 --- /dev/null +++ b/SOURCES/shadow-4.6-libsubid_fix_newusers_nss_provides_subids.patch @@ -0,0 +1,151 @@ +diff -up shadow-4.8.1/lib/nss.c.libsubid_fix_newusers_nss_provides_subids shadow-4.8.1/lib/nss.c +--- shadow-4.8.1/lib/nss.c.libsubid_fix_newusers_nss_provides_subids 2021-05-25 09:37:14.772741048 +0200 ++++ shadow-4.8.1/lib/nss.c 2021-05-25 09:37:14.782741188 +0200 +@@ -116,14 +116,6 @@ void nss_init(char *nsswitch_path) { + subid_nss = NULL; + goto done; + } +- subid_nss->has_any_range = dlsym(h, "shadow_subid_has_any_range"); +- if (!subid_nss->has_any_range) { +- fprintf(shadow_logfd, "%s did not provide @has_any_range@\n", libname); +- dlclose(h); +- free(subid_nss); +- subid_nss = NULL; +- goto done; +- } + subid_nss->find_subid_owners = dlsym(h, "shadow_subid_find_subid_owners"); + if (!subid_nss->find_subid_owners) { + fprintf(shadow_logfd, "%s did not provide @find_subid_owners@\n", libname); +diff -up shadow-4.8.1/lib/prototypes.h.libsubid_fix_newusers_nss_provides_subids shadow-4.8.1/lib/prototypes.h +--- shadow-4.8.1/lib/prototypes.h.libsubid_fix_newusers_nss_provides_subids 2021-05-25 09:37:14.780741160 +0200 ++++ shadow-4.8.1/lib/prototypes.h 2021-05-25 09:37:14.782741188 +0200 +@@ -279,18 +279,6 @@ extern bool nss_is_initialized(); + + struct subid_nss_ops { + /* +- * nss_has_any_range: does a user own any subid range +- * +- * @owner: username +- * @idtype: subuid or subgid +- * @result: true if a subid allocation was found for @owner +- * +- * returns success if the module was able to determine an answer (true or false), +- * else an error status. +- */ +- enum subid_status (*has_any_range)(const char *owner, enum subid_type idtype, bool *result); +- +- /* + * nss_has_range: does a user own a given subid range + * + * @owner: username +diff -up shadow-4.8.1/lib/subordinateio.c.libsubid_fix_newusers_nss_provides_subids shadow-4.8.1/lib/subordinateio.c +--- shadow-4.8.1/lib/subordinateio.c.libsubid_fix_newusers_nss_provides_subids 2021-05-25 09:37:14.780741160 +0200 ++++ shadow-4.8.1/lib/subordinateio.c 2021-05-25 09:37:14.782741188 +0200 +@@ -598,19 +598,8 @@ int sub_uid_open (int mode) + return commonio_open (&subordinate_uid_db, mode); + } + +-bool sub_uid_assigned(const char *owner) ++bool local_sub_uid_assigned(const char *owner) + { +- struct subid_nss_ops *h; +- bool found; +- enum subid_status status; +- h = get_subid_nss_handle(); +- if (h) { +- status = h->has_any_range(owner, ID_TYPE_UID, &found); +- if (status == SUBID_STATUS_SUCCESS && found) +- return true; +- return false; +- } +- + return range_exists (&subordinate_uid_db, owner); + } + +@@ -720,18 +709,8 @@ bool have_sub_gids(const char *owner, gi + return have_range(&subordinate_gid_db, owner, start, count); + } + +-bool sub_gid_assigned(const char *owner) ++bool local_sub_gid_assigned(const char *owner) + { +- struct subid_nss_ops *h; +- bool found; +- enum subid_status status; +- h = get_subid_nss_handle(); +- if (h) { +- status = h->has_any_range(owner, ID_TYPE_GID, &found); +- if (status == SUBID_STATUS_SUCCESS && found) +- return true; +- return false; +- } + return range_exists (&subordinate_gid_db, owner); + } + +diff -up shadow-4.8.1/lib/subordinateio.h.libsubid_fix_newusers_nss_provides_subids shadow-4.8.1/lib/subordinateio.h +--- shadow-4.8.1/lib/subordinateio.h.libsubid_fix_newusers_nss_provides_subids 2021-05-25 09:37:14.780741160 +0200 ++++ shadow-4.8.1/lib/subordinateio.h 2021-05-25 09:37:14.782741188 +0200 +@@ -16,7 +16,7 @@ + extern int sub_uid_close(void); + extern bool have_sub_uids(const char *owner, uid_t start, unsigned long count); + extern bool sub_uid_file_present (void); +-extern bool sub_uid_assigned(const char *owner); ++extern bool local_sub_uid_assigned(const char *owner); + extern int sub_uid_lock (void); + extern int sub_uid_setdbname (const char *filename); + extern /*@observer@*/const char *sub_uid_dbname (void); +@@ -34,7 +34,7 @@ extern void free_subordinate_ranges(stru + extern int sub_gid_close(void); + extern bool have_sub_gids(const char *owner, gid_t start, unsigned long count); + extern bool sub_gid_file_present (void); +-extern bool sub_gid_assigned(const char *owner); ++extern bool local_sub_gid_assigned(const char *owner); + extern int sub_gid_lock (void); + extern int sub_gid_setdbname (const char *filename); + extern /*@observer@*/const char *sub_gid_dbname (void); +diff -up shadow-4.8.1/src/newusers.c.libsubid_fix_newusers_nss_provides_subids shadow-4.8.1/src/newusers.c +--- shadow-4.8.1/src/newusers.c.libsubid_fix_newusers_nss_provides_subids 2021-05-25 09:37:14.776741104 +0200 ++++ shadow-4.8.1/src/newusers.c 2021-05-25 09:37:25.955897160 +0200 +@@ -1021,6 +1021,24 @@ static void close_files (void) + #endif /* ENABLE_SUBIDS */ + } + ++static bool want_subuids(void) ++{ ++ if (get_subid_nss_handle() != NULL) ++ return false; ++ if (getdef_ulong ("SUB_UID_COUNT", 65536) == 0) ++ return false; ++ return true; ++} ++ ++static bool want_subgids(void) ++{ ++ if (get_subid_nss_handle() != NULL) ++ return false; ++ if (getdef_ulong ("SUB_GID_COUNT", 65536) == 0) ++ return false; ++ return true; ++} ++ + int main (int argc, char **argv) + { + char buf[BUFSIZ]; +@@ -1250,7 +1268,7 @@ int main (int argc, char **argv) + /* + * Add subordinate uids if the user does not have them. + */ +- if (is_sub_uid && !sub_uid_assigned(fields[0])) { ++ if (is_sub_uid && want_subuids() && !local_sub_uid_assigned(fields[0])) { + uid_t sub_uid_start = 0; + unsigned long sub_uid_count = 0; + if (find_new_sub_uids(fields[0], &sub_uid_start, &sub_uid_count) == 0) { +@@ -1270,7 +1288,7 @@ int main (int argc, char **argv) + /* + * Add subordinate gids if the user does not have them. + */ +- if (is_sub_gid && !sub_gid_assigned(fields[0])) { ++ if (is_sub_gid && want_subgids() && !local_sub_gid_assigned(fields[0])) { + gid_t sub_gid_start = 0; + unsigned long sub_gid_count = 0; + if (find_new_sub_gids(fields[0], &sub_gid_start, &sub_gid_count) == 0) { diff --git a/SOURCES/shadow-4.6-libsubid_init_not_print_error_messages.patch b/SOURCES/shadow-4.6-libsubid_init_not_print_error_messages.patch new file mode 100644 index 0000000..820a043 --- /dev/null +++ b/SOURCES/shadow-4.6-libsubid_init_not_print_error_messages.patch @@ -0,0 +1,40 @@ +From b0e86b959fe5c086ffb5e7eaf3c1b1e9219411e9 Mon Sep 17 00:00:00 2001 +From: Serge Hallyn +Date: Sun, 23 May 2021 08:03:10 -0500 +Subject: [PATCH] libsubid_init: don't print messages on error + +Signed-off-by: Serge Hallyn +--- + libsubid/api.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/libsubid/api.c b/libsubid/api.c +index c4848142..b477b271 100644 +--- a/libsubid/api.c ++++ b/libsubid/api.c +@@ -46,12 +46,10 @@ bool libsubid_init(const char *progname, FILE * logfd) + { + if (progname) { + progname = strdup(progname); +- if (progname) { ++ if (progname) + Prog = progname; +- } else { +- fprintf(stderr, "Out of memory"); ++ else + return false; +- } + } + + if (logfd) { +@@ -60,7 +58,6 @@ bool libsubid_init(const char *progname, FILE * logfd) + } + shadow_logfd = fopen("/dev/null", "w"); + if (!shadow_logfd) { +- fprintf(stderr, "ERROR opening /dev/null for error messages. Using stderr."); + shadow_logfd = stderr; + return false; + } +-- +2.30.2 + diff --git a/SOURCES/shadow-4.6-libsubid_init_return_false.patch b/SOURCES/shadow-4.6-libsubid_init_return_false.patch new file mode 100644 index 0000000..4d02d0d --- /dev/null +++ b/SOURCES/shadow-4.6-libsubid_init_return_false.patch @@ -0,0 +1,37 @@ +From e34f49c1966fcaa9390a544a0136ec189a3c870e Mon Sep 17 00:00:00 2001 +From: Serge Hallyn +Date: Mon, 17 May 2021 08:48:03 -0500 +Subject: [PATCH] libsubid_init: return false if out of memory + +The rest of the run isn't likely to get much better, is it? + +Thanks to Alexey for pointing this out. + +Signed-off-by: Serge Hallyn +Cc: Alexey Tikhonov +--- + libsubid/api.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/libsubid/api.c b/libsubid/api.c +index 8ca09859..8618e500 100644 +--- a/libsubid/api.c ++++ b/libsubid/api.c +@@ -46,10 +46,12 @@ bool libsubid_init(const char *progname, FILE * logfd) + { + if (progname) { + progname = strdup(progname); +- if (progname) ++ if (progname) { + Prog = progname; +- else ++ } else { + fprintf(stderr, "Out of memory"); ++ return false; ++ } + } + + if (logfd) { +-- +2.30.2 + diff --git a/SOURCES/shadow-4.6-libsubid_make_logfd_not_extern.patch b/SOURCES/shadow-4.6-libsubid_make_logfd_not_extern.patch new file mode 100644 index 0000000..2994442 --- /dev/null +++ b/SOURCES/shadow-4.6-libsubid_make_logfd_not_extern.patch @@ -0,0 +1,41 @@ +From 1d767fb779d7b203ad609540d1dc605cf62d1050 Mon Sep 17 00:00:00 2001 +From: Serge Hallyn +Date: Fri, 28 May 2021 22:02:16 -0500 +Subject: [PATCH] libsubid/api.c: make shadow_logfd not extern + +Closes #346 + +Also #include stdio.h + +Signed-off-by: Serge Hallyn +--- + libsubid/api.c | 2 +- + libsubid/subid.h | 1 + + 2 files changed, 2 insertions(+), 1 deletion(-) + +diff --git a/libsubid/api.c b/libsubid/api.c +index b477b271..a7b904d0 100644 +--- a/libsubid/api.c ++++ b/libsubid/api.c +@@ -40,7 +40,7 @@ + #include "subid.h" + + const char *Prog = "(libsubid)"; +-extern FILE * shadow_logfd; ++FILE *shadow_logfd; + + bool libsubid_init(const char *progname, FILE * logfd) + { +diff --git a/libsubid/subid.h b/libsubid/subid.h +index 5fef2572..eabafe4d 100644 +--- a/libsubid/subid.h ++++ b/libsubid/subid.h +@@ -1,4 +1,5 @@ + #include ++#include + #include + + #ifndef SUBID_RANGE_DEFINED +-- +2.31.1 + diff --git a/SOURCES/shadow-4.6-libsubid_not_print_error_messages.patch b/SOURCES/shadow-4.6-libsubid_not_print_error_messages.patch new file mode 100644 index 0000000..2d4faa3 --- /dev/null +++ b/SOURCES/shadow-4.6-libsubid_not_print_error_messages.patch @@ -0,0 +1,2382 @@ +diff -up shadow-4.6/lib/commonio.c.libsubid_not_print_error_messages shadow-4.6/lib/commonio.c +--- shadow-4.6/lib/commonio.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.668172672 +0100 ++++ shadow-4.6/lib/commonio.c 2021-11-03 09:28:20.444277611 +0100 +@@ -147,7 +147,7 @@ static int do_lock_file (const char *fil + fd = open (file, O_CREAT | O_TRUNC | O_WRONLY, 0600); + if (-1 == fd) { + if (log) { +- (void) fprintf (stderr, ++ (void) fprintf (shadow_logfd, + "%s: %s: %s\n", + Prog, file, strerror (errno)); + } +@@ -159,7 +159,7 @@ static int do_lock_file (const char *fil + len = (ssize_t) strlen (buf) + 1; + if (write (fd, buf, (size_t) len) != len) { + if (log) { +- (void) fprintf (stderr, ++ (void) fprintf (shadow_logfd, + "%s: %s: %s\n", + Prog, file, strerror (errno)); + } +@@ -172,7 +172,7 @@ static int do_lock_file (const char *fil + if (link (file, lock) == 0) { + retval = check_link_count (file); + if ((0==retval) && log) { +- (void) fprintf (stderr, ++ (void) fprintf (shadow_logfd, + "%s: %s: lock file already used\n", + Prog, file); + } +@@ -183,7 +183,7 @@ static int do_lock_file (const char *fil + fd = open (lock, O_RDWR); + if (-1 == fd) { + if (log) { +- (void) fprintf (stderr, ++ (void) fprintf (shadow_logfd, + "%s: %s: %s\n", + Prog, lock, strerror (errno)); + } +@@ -195,7 +195,7 @@ static int do_lock_file (const char *fil + close (fd); + if (len <= 0) { + if (log) { +- (void) fprintf (stderr, ++ (void) fprintf (shadow_logfd, + "%s: existing lock file %s without a PID\n", + Prog, lock); + } +@@ -206,7 +206,7 @@ static int do_lock_file (const char *fil + buf[len] = '\0'; + if (get_pid (buf, &pid) == 0) { + if (log) { +- (void) fprintf (stderr, ++ (void) fprintf (shadow_logfd, + "%s: existing lock file %s with an invalid PID '%s'\n", + Prog, lock, buf); + } +@@ -216,7 +216,7 @@ static int do_lock_file (const char *fil + } + if (kill (pid, 0) == 0) { + if (log) { +- (void) fprintf (stderr, ++ (void) fprintf (shadow_logfd, + "%s: lock %s already used by PID %lu\n", + Prog, lock, (unsigned long) pid); + } +@@ -226,7 +226,7 @@ static int do_lock_file (const char *fil + } + if (unlink (lock) != 0) { + if (log) { +- (void) fprintf (stderr, ++ (void) fprintf (shadow_logfd, + "%s: cannot get lock %s: %s\n", + Prog, lock, strerror (errno)); + } +@@ -238,13 +238,13 @@ static int do_lock_file (const char *fil + if (link (file, lock) == 0) { + retval = check_link_count (file); + if ((0==retval) && log) { +- (void) fprintf (stderr, ++ (void) fprintf (shadow_logfd, + "%s: %s: lock file already used\n", + Prog, file); + } + } else { + if (log) { +- (void) fprintf (stderr, ++ (void) fprintf (shadow_logfd, + "%s: cannot get lock %s: %s\n", + Prog, lock, strerror (errno)); + } +@@ -435,7 +435,7 @@ int commonio_lock (struct commonio_db *d + if (0 == lock_count) { + if (lckpwdf () == -1) { + if (geteuid () != 0) { +- (void) fprintf (stderr, ++ (void) fprintf (shadow_logfd, + "%s: Permission denied.\n", + Prog); + } +@@ -471,7 +471,7 @@ int commonio_lock (struct commonio_db *d + } + /* no unnecessary retries on "permission denied" errors */ + if (geteuid () != 0) { +- (void) fprintf (stderr, "%s: Permission denied.\n", ++ (void) fprintf (shadow_logfd, "%s: Permission denied.\n", + Prog); + return 0; + } +@@ -1101,7 +1101,7 @@ int commonio_update (struct commonio_db + p = find_entry_by_name (db, db->ops->getname (eptr)); + if (NULL != p) { + if (next_entry_by_name (db, p->next, db->ops->getname (eptr)) != NULL) { +- fprintf (stderr, _("Multiple entries named '%s' in %s. Please fix this with pwck or grpck.\n"), db->ops->getname (eptr), db->filename); ++ fprintf (shadow_logfd, _("Multiple entries named '%s' in %s. Please fix this with pwck or grpck.\n"), db->ops->getname (eptr), db->filename); + db->ops->free (nentry); + return 0; + } +@@ -1206,7 +1206,7 @@ int commonio_remove (struct commonio_db + return 0; + } + if (next_entry_by_name (db, p->next, name) != NULL) { +- fprintf (stderr, _("Multiple entries named '%s' in %s. Please fix this with pwck or grpck.\n"), name, db->filename); ++ fprintf (shadow_logfd, _("Multiple entries named '%s' in %s. Please fix this with pwck or grpck.\n"), name, db->filename); + return 0; + } + +diff -up shadow-4.6/lib/encrypt.c.libsubid_not_print_error_messages shadow-4.6/lib/encrypt.c +--- shadow-4.6/lib/encrypt.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/lib/encrypt.c 2021-11-03 09:24:05.681172775 +0100 +@@ -78,7 +78,7 @@ + method = &nummethod[0]; + } + } +- (void) fprintf (stderr, ++ (void) fprintf (shadow_logfd, + _("crypt method not supported by libcrypt? (%s)\n"), + method); + exit (EXIT_FAILURE); +diff -up shadow-4.6/lib/getdef.c.libsubid_not_print_error_messages shadow-4.6/lib/getdef.c +--- shadow-4.6/lib/getdef.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.670172687 +0100 ++++ shadow-4.6/lib/getdef.c 2021-11-03 09:24:05.681172775 +0100 +@@ -233,7 +233,7 @@ int getdef_num (const char *item, int df + if ( (getlong (d->value, &val) == 0) + || (val > INT_MAX) + || (val < INT_MIN)) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("configuration error - cannot parse %s value: '%s'"), + item, d->value); + return dflt; +@@ -268,7 +268,7 @@ unsigned int getdef_unum (const char *it + if ( (getlong (d->value, &val) == 0) + || (val < 0) + || (val > INT_MAX)) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("configuration error - cannot parse %s value: '%s'"), + item, d->value); + return dflt; +@@ -301,7 +301,7 @@ long getdef_long (const char *item, long + } + + if (getlong (d->value, &val) == 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("configuration error - cannot parse %s value: '%s'"), + item, d->value); + return dflt; +@@ -334,7 +334,7 @@ unsigned long getdef_ulong (const char * + + if (getulong (d->value, &val) == 0) { + /* FIXME: we should have a getulong */ +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("configuration error - cannot parse %s value: '%s'"), + item, d->value); + return dflt; +@@ -372,7 +372,7 @@ int putdef_str (const char *name, const + cp = strdup (value); + if (NULL == cp) { + (void) fputs (_("Could not allocate space for config info.\n"), +- stderr); ++ shadow_logfd); + SYSLOG ((LOG_ERR, "could not allocate space for config info")); + return -1; + } +@@ -417,7 +417,7 @@ static /*@observer@*/ /*@null@*/struct i + goto out; + } + } +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("configuration error - unknown item '%s' (notify administrator)\n"), + name); + SYSLOG ((LOG_CRIT, "unknown configuration item `%s'", name)); +diff -up shadow-4.6/libmisc/addgrps.c.libsubid_not_print_error_messages shadow-4.6/libmisc/addgrps.c +--- shadow-4.6/libmisc/addgrps.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/libmisc/addgrps.c 2021-11-03 09:24:05.681172775 +0100 +@@ -93,7 +93,7 @@ int add_groups (const char *list) + + grp = getgrnam (token); /* local, no need for xgetgrnam */ + if (NULL == grp) { +- fprintf (stderr, _("Warning: unknown group %s\n"), ++ fprintf (shadow_logfd, _("Warning: unknown group %s\n"), + token); + continue; + } +@@ -105,7 +105,7 @@ int add_groups (const char *list) + } + + if (ngroups >= sysconf (_SC_NGROUPS_MAX)) { +- fputs (_("Warning: too many groups\n"), stderr); ++ fputs (_("Warning: too many groups\n"), shadow_logfd); + break; + } + tmp = (gid_t *) realloc (grouplist, (size_t)(ngroups + 1) * sizeof (GETGROUPS_T)); +diff -up shadow-4.6/libmisc/audit_help.c.libsubid_not_print_error_messages shadow-4.6/libmisc/audit_help.c +--- shadow-4.6/libmisc/audit_help.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.649172520 +0100 ++++ shadow-4.6/libmisc/audit_help.c 2021-11-03 09:24:05.681172775 +0100 +@@ -59,7 +59,7 @@ void audit_help_open (void) + return; + } + (void) fputs (_("Cannot open audit interface - aborting.\n"), +- stderr); ++ shadow_logfd); + exit (EXIT_FAILURE); + } + } +diff -up shadow-4.6/libmisc/chowntty.c.libsubid_not_print_error_messages shadow-4.6/libmisc/chowntty.c +--- shadow-4.6/libmisc/chowntty.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/libmisc/chowntty.c 2021-11-03 09:24:05.681172775 +0100 +@@ -75,7 +75,7 @@ void chown_tty (const struct passwd *inf + || (fchmod (STDIN_FILENO, (mode_t)getdef_num ("TTYPERM", 0600)) != 0)) { + int err = errno; + +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("Unable to change owner or mode of tty stdin: %s"), + strerror (err)); + SYSLOG ((LOG_WARN, +diff -up shadow-4.6/libmisc/cleanup_group.c.libsubid_not_print_error_messages shadow-4.6/libmisc/cleanup_group.c +--- shadow-4.6/libmisc/cleanup_group.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.649172520 +0100 ++++ shadow-4.6/libmisc/cleanup_group.c 2021-11-03 09:24:05.681172775 +0100 +@@ -203,7 +203,7 @@ void cleanup_report_del_group_gshadow (v + void cleanup_unlock_group (unused void *arg) + { + if (gr_unlock () == 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: failed to unlock %s\n"), + Prog, gr_dbname ()); + SYSLOG ((LOG_ERR, "failed to unlock %s", gr_dbname ())); +@@ -223,7 +223,7 @@ void cleanup_unlock_group (unused void * + void cleanup_unlock_gshadow (unused void *arg) + { + if (sgr_unlock () == 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: failed to unlock %s\n"), + Prog, sgr_dbname ()); + SYSLOG ((LOG_ERR, "failed to unlock %s", sgr_dbname ())); +diff -up shadow-4.6/libmisc/cleanup_user.c.libsubid_not_print_error_messages shadow-4.6/libmisc/cleanup_user.c +--- shadow-4.6/libmisc/cleanup_user.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.649172520 +0100 ++++ shadow-4.6/libmisc/cleanup_user.c 2021-11-03 09:24:05.682172783 +0100 +@@ -120,7 +120,7 @@ void cleanup_report_add_user_shadow (voi + void cleanup_unlock_passwd (unused void *arg) + { + if (pw_unlock () == 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: failed to unlock %s\n"), + Prog, pw_dbname ()); + SYSLOG ((LOG_ERR, "failed to unlock %s", pw_dbname ())); +@@ -139,7 +139,7 @@ void cleanup_unlock_passwd (unused void + void cleanup_unlock_shadow (unused void *arg) + { + if (spw_unlock () == 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: failed to unlock %s\n"), + Prog, spw_dbname ()); + SYSLOG ((LOG_ERR, "failed to unlock %s", spw_dbname ())); +diff -up shadow-4.6/libmisc/copydir.c.libsubid_not_print_error_messages shadow-4.6/libmisc/copydir.c +--- shadow-4.6/libmisc/copydir.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.642172465 +0100 ++++ shadow-4.6/libmisc/copydir.c 2021-11-03 09:24:05.682172783 +0100 +@@ -125,11 +125,11 @@ static void error_acl (struct error_cont + } + + va_start (ap, fmt); +- (void) fprintf (stderr, _("%s: "), Prog); +- if (vfprintf (stderr, fmt, ap) != 0) { +- (void) fputs (_(": "), stderr); ++ (void) fprintf (shadow_logfd, _("%s: "), Prog); ++ if (vfprintf (shadow_logfd, fmt, ap) != 0) { ++ (void) fputs (_(": "), shadow_logfd); + } +- (void) fprintf (stderr, "%s\n", strerror (errno)); ++ (void) fprintf (shadow_logfd, "%s\n", strerror (errno)); + va_end (ap); + } + +@@ -248,7 +248,7 @@ int copy_tree (const char *src_root, con + } + + if (!S_ISDIR (sb.st_mode)) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + "%s: %s is not a directory", + Prog, src_root); + return -1; +diff -up shadow-4.6/libmisc/env.c.libsubid_not_print_error_messages shadow-4.6/libmisc/env.c +--- shadow-4.6/libmisc/env.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/libmisc/env.c 2021-11-03 09:24:05.682172783 +0100 +@@ -171,7 +171,7 @@ void addenv (const char *string, /*@null + } + newenvp = __newenvp; + } else { +- (void) fputs (_("Environment overflow\n"), stderr); ++ (void) fputs (_("Environment overflow\n"), shadow_logfd); + newenvc--; + free (newenvp[newenvc]); + } +diff -up shadow-4.6/libmisc/find_new_gid.c.libsubid_not_print_error_messages shadow-4.6/libmisc/find_new_gid.c +--- shadow-4.6/libmisc/find_new_gid.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.665172648 +0100 ++++ shadow-4.6/libmisc/find_new_gid.c 2021-11-03 09:24:05.682172783 +0100 +@@ -74,7 +74,7 @@ static int get_ranges (bool sys_group, g + + /* Check that the ranges make sense */ + if (*max_id < *min_id) { +- (void) fprintf (stderr, ++ (void) fprintf (shadow_logfd, + _("%s: Invalid configuration: SYS_GID_MIN (%lu), " + "GID_MIN (%lu), SYS_GID_MAX (%lu)\n"), + Prog, (unsigned long) *min_id, +@@ -104,7 +104,7 @@ static int get_ranges (bool sys_group, g + + /* Check that the ranges make sense */ + if (*max_id < *min_id) { +- (void) fprintf (stderr, ++ (void) fprintf (shadow_logfd, + _("%s: Invalid configuration: GID_MIN (%lu), " + "GID_MAX (%lu)\n"), + Prog, (unsigned long) *min_id, +@@ -220,7 +220,7 @@ int find_new_gid (bool sys_group, + * more likely to want to stop and address the + * issue. + */ +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Encountered error attempting to use " + "preferred GID: %s\n"), + Prog, strerror (result)); +@@ -250,7 +250,7 @@ int find_new_gid (bool sys_group, + /* Create an array to hold all of the discovered GIDs */ + used_gids = malloc (sizeof (bool) * (gid_max +1)); + if (NULL == used_gids) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: failed to allocate memory: %s\n"), + Prog, strerror (errno)); + return -1; +@@ -330,7 +330,7 @@ int find_new_gid (bool sys_group, + * + */ + if (!nospam) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Can't get unique system GID (%s). " + "Suppressing additional messages.\n"), + Prog, strerror (result)); +@@ -373,7 +373,7 @@ int find_new_gid (bool sys_group, + * + */ + if (!nospam) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Can't get unique system GID (%s). " + "Suppressing additional messages.\n"), + Prog, strerror (result)); +@@ -433,7 +433,7 @@ int find_new_gid (bool sys_group, + * + */ + if (!nospam) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Can't get unique GID (%s). " + "Suppressing additional messages.\n"), + Prog, strerror (result)); +@@ -476,7 +476,7 @@ int find_new_gid (bool sys_group, + * + */ + if (!nospam) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Can't get unique GID (%s). " + "Suppressing additional messages.\n"), + Prog, strerror (result)); +@@ -495,7 +495,7 @@ int find_new_gid (bool sys_group, + } + + /* The code reached here and found no available IDs in the range */ +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Can't get unique GID (no more available GIDs)\n"), + Prog); + SYSLOG ((LOG_WARN, "no more available GIDs on the system")); +diff -up shadow-4.6/libmisc/find_new_sub_gids.c.libsubid_not_print_error_messages shadow-4.6/libmisc/find_new_sub_gids.c +--- shadow-4.6/libmisc/find_new_sub_gids.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/libmisc/find_new_sub_gids.c 2021-11-03 09:24:05.682172783 +0100 +@@ -61,7 +61,7 @@ int find_new_sub_gids (const char *owner + count = getdef_ulong ("SUB_GID_COUNT", 65536); + + if (min > max || count >= max || (min + count - 1) > max) { +- (void) fprintf (stderr, ++ (void) fprintf (shadow_logfd, + _("%s: Invalid configuration: SUB_GID_MIN (%lu)," + " SUB_GID_MAX (%lu), SUB_GID_COUNT (%lu)\n"), + Prog, min, max, count); +@@ -70,7 +70,7 @@ int find_new_sub_gids (const char *owner + + start = sub_gid_find_free_range(min, max, count); + if (start == (gid_t)-1) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Can't get unique subordinate GID range\n"), + Prog); + SYSLOG ((LOG_WARN, "no more available subordinate GIDs on the system")); +diff -up shadow-4.6/libmisc/find_new_sub_uids.c.libsubid_not_print_error_messages shadow-4.6/libmisc/find_new_sub_uids.c +--- shadow-4.6/libmisc/find_new_sub_uids.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/libmisc/find_new_sub_uids.c 2021-11-03 09:24:05.682172783 +0100 +@@ -61,7 +61,7 @@ int find_new_sub_uids (const char *owner + count = getdef_ulong ("SUB_UID_COUNT", 65536); + + if (min > max || count >= max || (min + count - 1) > max) { +- (void) fprintf (stderr, ++ (void) fprintf (shadow_logfd, + _("%s: Invalid configuration: SUB_UID_MIN (%lu)," + " SUB_UID_MAX (%lu), SUB_UID_COUNT (%lu)\n"), + Prog, min, max, count); +@@ -70,7 +70,7 @@ int find_new_sub_uids (const char *owner + + start = sub_uid_find_free_range(min, max, count); + if (start == (uid_t)-1) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Can't get unique subordinate UID range\n"), + Prog); + SYSLOG ((LOG_WARN, "no more available subordinate UIDs on the system")); +diff -up shadow-4.6/libmisc/find_new_uid.c.libsubid_not_print_error_messages shadow-4.6/libmisc/find_new_uid.c +--- shadow-4.6/libmisc/find_new_uid.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.665172648 +0100 ++++ shadow-4.6/libmisc/find_new_uid.c 2021-11-03 09:24:05.682172783 +0100 +@@ -74,7 +74,7 @@ static int get_ranges (bool sys_user, ui + + /* Check that the ranges make sense */ + if (*max_id < *min_id) { +- (void) fprintf (stderr, ++ (void) fprintf (shadow_logfd, + _("%s: Invalid configuration: SYS_UID_MIN (%lu), " + "UID_MIN (%lu), SYS_UID_MAX (%lu)\n"), + Prog, (unsigned long) *min_id, +@@ -104,7 +104,7 @@ static int get_ranges (bool sys_user, ui + + /* Check that the ranges make sense */ + if (*max_id < *min_id) { +- (void) fprintf (stderr, ++ (void) fprintf (shadow_logfd, + _("%s: Invalid configuration: UID_MIN (%lu), " + "UID_MAX (%lu)\n"), + Prog, (unsigned long) *min_id, +@@ -220,7 +220,7 @@ int find_new_uid(bool sys_user, + * more likely to want to stop and address the + * issue. + */ +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Encountered error attempting to use " + "preferred UID: %s\n"), + Prog, strerror (result)); +@@ -250,7 +250,7 @@ int find_new_uid(bool sys_user, + /* Create an array to hold all of the discovered UIDs */ + used_uids = malloc (sizeof (bool) * (uid_max +1)); + if (NULL == used_uids) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: failed to allocate memory: %s\n"), + Prog, strerror (errno)); + return -1; +@@ -330,7 +330,7 @@ int find_new_uid(bool sys_user, + * + */ + if (!nospam) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Can't get unique system UID (%s). " + "Suppressing additional messages.\n"), + Prog, strerror (result)); +@@ -373,7 +373,7 @@ int find_new_uid(bool sys_user, + * + */ + if (!nospam) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Can't get unique system UID (%s). " + "Suppressing additional messages.\n"), + Prog, strerror (result)); +@@ -433,7 +433,7 @@ int find_new_uid(bool sys_user, + * + */ + if (!nospam) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Can't get unique UID (%s). " + "Suppressing additional messages.\n"), + Prog, strerror (result)); +@@ -476,7 +476,7 @@ int find_new_uid(bool sys_user, + * + */ + if (!nospam) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Can't get unique UID (%s). " + "Suppressing additional messages.\n"), + Prog, strerror (result)); +@@ -495,7 +495,7 @@ int find_new_uid(bool sys_user, + } + + /* The code reached here and found no available IDs in the range */ +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Can't get unique UID (no more available UIDs)\n"), + Prog); + SYSLOG ((LOG_WARN, "no more available UIDs on the system")); +diff -up shadow-4.6/libmisc/gettime.c.libsubid_not_print_error_messages shadow-4.6/libmisc/gettime.c +--- shadow-4.6/libmisc/gettime.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/libmisc/gettime.c 2021-11-03 09:24:05.682172783 +0100 +@@ -61,23 +61,23 @@ + epoch = strtoull (source_date_epoch, &endptr, 10); + if ((errno == ERANGE && (epoch == ULLONG_MAX || epoch == 0)) + || (errno != 0 && epoch == 0)) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("Environment variable $SOURCE_DATE_EPOCH: strtoull: %s\n"), + strerror(errno)); + } else if (endptr == source_date_epoch) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("Environment variable $SOURCE_DATE_EPOCH: No digits were found: %s\n"), + endptr); + } else if (*endptr != '\0') { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("Environment variable $SOURCE_DATE_EPOCH: Trailing garbage: %s\n"), + endptr); + } else if (epoch > ULONG_MAX) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("Environment variable $SOURCE_DATE_EPOCH: value must be smaller than or equal to %lu but was found to be: %llu\n"), + ULONG_MAX, epoch); + } else if (epoch > fallback) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("Environment variable $SOURCE_DATE_EPOCH: value must be smaller than or equal to the current time (%lu) but was found to be: %llu\n"), + fallback, epoch); + } else { +diff -up shadow-4.6/libmisc/idmapping.c.libsubid_not_print_error_messages shadow-4.6/libmisc/idmapping.c +--- shadow-4.6/libmisc/idmapping.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/libmisc/idmapping.c 2021-11-03 09:24:05.682172783 +0100 +@@ -43,19 +43,19 @@ struct map_range *get_map_ranges(int ran + int idx, argidx; + + if (ranges < 0 || argc < 0) { +- fprintf(stderr, "%s: error calculating number of arguments\n", Prog); ++ fprintf(shadow_logfd, "%s: error calculating number of arguments\n", Prog); + return NULL; + } + + if (ranges != ((argc + 2) / 3)) { +- fprintf(stderr, "%s: ranges: %u is wrong for argc: %d\n", Prog, ranges, argc); ++ fprintf(shadow_logfd, "%s: ranges: %u is wrong for argc: %d\n", Prog, ranges, argc); + return NULL; + } + + if ((ranges * 3) > argc) { +- fprintf(stderr, "ranges: %u argc: %d\n", ++ fprintf(shadow_logfd, "ranges: %u argc: %d\n", + ranges, argc); +- fprintf(stderr, ++ fprintf(shadow_logfd, + _( "%s: Not enough arguments to form %u mappings\n"), + Prog, ranges); + return NULL; +@@ -63,7 +63,7 @@ struct map_range *get_map_ranges(int ran + + mappings = calloc(ranges, sizeof(*mappings)); + if (!mappings) { +- fprintf(stderr, _( "%s: Memory allocation failure\n"), ++ fprintf(shadow_logfd, _( "%s: Memory allocation failure\n"), + Prog); + exit(EXIT_FAILURE); + } +@@ -84,24 +84,24 @@ struct map_range *get_map_ranges(int ran + return NULL; + } + if (ULONG_MAX - mapping->upper <= mapping->count || ULONG_MAX - mapping->lower <= mapping->count) { +- fprintf(stderr, _( "%s: subuid overflow detected.\n"), Prog); ++ fprintf(shadow_logfd, _( "%s: subuid overflow detected.\n"), Prog); + exit(EXIT_FAILURE); + } + if (mapping->upper > UINT_MAX || + mapping->lower > UINT_MAX || + mapping->count > UINT_MAX) { +- fprintf(stderr, _( "%s: subuid overflow detected.\n"), Prog); ++ fprintf(shadow_logfd, _( "%s: subuid overflow detected.\n"), Prog); + exit(EXIT_FAILURE); + } + if (mapping->lower + mapping->count > UINT_MAX || + mapping->upper + mapping->count > UINT_MAX) { +- fprintf(stderr, _( "%s: subuid overflow detected.\n"), Prog); ++ fprintf(shadow_logfd, _( "%s: subuid overflow detected.\n"), Prog); + exit(EXIT_FAILURE); + } + if (mapping->lower + mapping->count < mapping->lower || + mapping->upper + mapping->count < mapping->upper) { + /* this one really shouldn't be possible given previous checks */ +- fprintf(stderr, _( "%s: subuid overflow detected.\n"), Prog); ++ fprintf(shadow_logfd, _( "%s: subuid overflow detected.\n"), Prog); + exit(EXIT_FAILURE); + } + } +@@ -142,7 +142,7 @@ void write_mapping(int proc_dir_fd, int + mapping->lower, + mapping->count); + if ((written <= 0) || (written >= (bufsize - (pos - buf)))) { +- fprintf(stderr, _("%s: snprintf failed!\n"), Prog); ++ fprintf(shadow_logfd, _("%s: snprintf failed!\n"), Prog); + exit(EXIT_FAILURE); + } + pos += written; +@@ -151,12 +151,12 @@ void write_mapping(int proc_dir_fd, int + /* Write the mapping to the mapping file */ + fd = openat(proc_dir_fd, map_file, O_WRONLY); + if (fd < 0) { +- fprintf(stderr, _("%s: open of %s failed: %s\n"), ++ fprintf(shadow_logfd, _("%s: open of %s failed: %s\n"), + Prog, map_file, strerror(errno)); + exit(EXIT_FAILURE); + } + if (write(fd, buf, pos - buf) != (pos - buf)) { +- fprintf(stderr, _("%s: write to %s failed: %s\n"), ++ fprintf(shadow_logfd, _("%s: write to %s failed: %s\n"), + Prog, map_file, strerror(errno)); + exit(EXIT_FAILURE); + } +diff -up shadow-4.6/libmisc/limits.c.libsubid_not_print_error_messages shadow-4.6/libmisc/limits.c +--- shadow-4.6/libmisc/limits.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/libmisc/limits.c 2021-11-03 09:24:05.682172783 +0100 +@@ -548,7 +548,7 @@ void setup_limits (const struct passwd * + #ifdef LIMITS + if (info->pw_uid != 0) { + if ((setup_user_limits (info->pw_name) & LOGIN_ERROR_LOGIN) != 0) { +- (void) fputs (_("Too many logins.\n"), stderr); ++ (void) fputs (_("Too many logins.\n"), shadow_logfd); + (void) sleep (2); /* XXX: Should be FAIL_DELAY */ + exit (EXIT_FAILURE); + } +diff -up shadow-4.6/libmisc/pam_pass.c.libsubid_not_print_error_messages shadow-4.6/libmisc/pam_pass.c +--- shadow-4.6/libmisc/pam_pass.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/libmisc/pam_pass.c 2021-11-03 09:24:05.682172783 +0100 +@@ -59,20 +59,20 @@ void do_pam_passwd (const char *user, bo + + ret = pam_start ("passwd", user, &conv, &pamh); + if (ret != PAM_SUCCESS) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("passwd: pam_start() failed, error %d\n"), ret); + exit (10); /* XXX */ + } + + ret = pam_chauthtok (pamh, flags); + if (ret != PAM_SUCCESS) { +- fprintf (stderr, _("passwd: %s\n"), pam_strerror (pamh, ret)); +- fputs (_("passwd: password unchanged\n"), stderr); ++ fprintf (shadow_logfd, _("passwd: %s\n"), pam_strerror (pamh, ret)); ++ fputs (_("passwd: password unchanged\n"), shadow_logfd); + pam_end (pamh, ret); + exit (10); /* XXX */ + } + +- fputs (_("passwd: password updated successfully\n"), stderr); ++ fputs (_("passwd: password updated successfully\n"), shadow_logfd); + (void) pam_end (pamh, PAM_SUCCESS); + } + #else /* !USE_PAM */ +diff -up shadow-4.6/libmisc/pam_pass_non_interactive.c.libsubid_not_print_error_messages shadow-4.6/libmisc/pam_pass_non_interactive.c +--- shadow-4.6/libmisc/pam_pass_non_interactive.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/libmisc/pam_pass_non_interactive.c 2021-11-03 09:24:05.683172791 +0100 +@@ -76,7 +76,7 @@ static int ni_conv (int num_msg, + + switch (msg[count]->msg_style) { + case PAM_PROMPT_ECHO_ON: +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: PAM modules requesting echoing are not supported.\n"), + Prog); + goto failed_conversation; +@@ -88,7 +88,7 @@ static int ni_conv (int num_msg, + break; + case PAM_ERROR_MSG: + if ( (NULL == msg[count]->msg) +- || (fprintf (stderr, "%s\n", msg[count]->msg) <0)) { ++ || (fprintf (shadow_logfd, "%s\n", msg[count]->msg) <0)) { + goto failed_conversation; + } + responses[count].resp = NULL; +@@ -101,7 +101,7 @@ static int ni_conv (int num_msg, + responses[count].resp = NULL; + break; + default: +- (void) fprintf (stderr, ++ (void) fprintf (shadow_logfd, + _("%s: conversation type %d not supported.\n"), + Prog, msg[count]->msg_style); + goto failed_conversation; +@@ -143,7 +143,7 @@ int do_pam_passwd_non_interactive (const + + ret = pam_start (pam_service, username, &non_interactive_pam_conv, &pamh); + if (ret != PAM_SUCCESS) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: (user %s) pam_start failure %d\n"), + Prog, username, ret); + return 1; +@@ -152,7 +152,7 @@ int do_pam_passwd_non_interactive (const + non_interactive_password = password; + ret = pam_chauthtok (pamh, 0); + if (ret != PAM_SUCCESS) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: (user %s) pam_chauthtok() failed, error:\n" + "%s\n"), + Prog, username, pam_strerror (pamh, ret)); +diff -up shadow-4.6/libmisc/prefix_flag.c.libsubid_not_print_error_messages shadow-4.6/libmisc/prefix_flag.c +--- shadow-4.6/libmisc/prefix_flag.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.658172592 +0100 ++++ shadow-4.6/libmisc/prefix_flag.c 2021-11-03 09:24:05.683172791 +0100 +@@ -80,14 +80,14 @@ extern const char* process_prefix_flag ( + if ( (strcmp (argv[i], "--prefix") == 0) + || (strcmp (argv[i], short_opt) == 0)) { + if (NULL != prefix) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: multiple --prefix options\n"), + Prog); + exit (E_BAD_ARG); + } + + if (i + 1 == argc) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: option '%s' requires an argument\n"), + Prog, argv[i]); + exit (E_BAD_ARG); +diff -up shadow-4.6/libmisc/pwdcheck.c.libsubid_not_print_error_messages shadow-4.6/libmisc/pwdcheck.c +--- shadow-4.6/libmisc/pwdcheck.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/libmisc/pwdcheck.c 2021-11-03 09:24:05.683172791 +0100 +@@ -51,7 +51,7 @@ void passwd_check (const char *user, con + if (pw_auth (passwd, user, PW_LOGIN, (char *) 0) != 0) { + SYSLOG ((LOG_WARN, "incorrect password for `%s'", user)); + (void) sleep (1); +- fprintf (stderr, _("Incorrect password for %s.\n"), user); ++ fprintf (shadow_logfd, _("Incorrect password for %s.\n"), user); + exit (EXIT_FAILURE); + } + } +diff -up shadow-4.6/libmisc/root_flag.c.libsubid_not_print_error_messages shadow-4.6/libmisc/root_flag.c +--- shadow-4.6/libmisc/root_flag.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/libmisc/root_flag.c 2021-11-03 09:24:05.683172791 +0100 +@@ -62,14 +62,14 @@ extern void process_root_flag (const cha + if ( (strcmp (argv[i], "--root") == 0) + || (strcmp (argv[i], short_opt) == 0)) { + if (NULL != newroot) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: multiple --root options\n"), + Prog); + exit (E_BAD_ARG); + } + + if (i + 1 == argc) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: option '%s' requires an argument\n"), + Prog, argv[i]); + exit (E_BAD_ARG); +@@ -88,34 +88,34 @@ static void change_root (const char* new + /* Drop privileges */ + if ( (setregid (getgid (), getgid ()) != 0) + || (setreuid (getuid (), getuid ()) != 0)) { +- fprintf (stderr, _("%s: failed to drop privileges (%s)\n"), ++ fprintf (shadow_logfd, _("%s: failed to drop privileges (%s)\n"), + Prog, strerror (errno)); + exit (EXIT_FAILURE); + } + + if ('/' != newroot[0]) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: invalid chroot path '%s'\n"), + Prog, newroot); + exit (E_BAD_ARG); + } + + if (access (newroot, F_OK) != 0) { +- fprintf(stderr, ++ fprintf(shadow_logfd, + _("%s: cannot access chroot directory %s: %s\n"), + Prog, newroot, strerror (errno)); + exit (E_BAD_ARG); + } + + if (chdir (newroot) != 0) { +- fprintf(stderr, ++ fprintf(shadow_logfd, + _("%s: cannot chdir to chroot directory %s: %s\n"), + Prog, newroot, strerror (errno)); + exit (E_BAD_ARG); + } + + if (chroot (newroot) != 0) { +- fprintf(stderr, ++ fprintf(shadow_logfd, + _("%s: unable to chroot to directory %s: %s\n"), + Prog, newroot, strerror (errno)); + exit (E_BAD_ARG); +diff -up shadow-4.6/libmisc/salt.c.libsubid_not_print_error_messages shadow-4.6/libmisc/salt.c +--- shadow-4.6/libmisc/salt.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/libmisc/salt.c 2021-11-03 09:24:05.683172791 +0100 +@@ -241,7 +241,7 @@ static /*@observer@*/const char *gensalt + salt_len = (size_t) shadow_random (8, 16); + #endif /* USE_SHA_CRYPT */ + } else if (0 != strcmp (method, "DES")) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("Invalid ENCRYPT_METHOD value: '%s'.\n" + "Defaulting to DES.\n"), + method); +diff -up shadow-4.6/libmisc/setupenv.c.libsubid_not_print_error_messages shadow-4.6/libmisc/setupenv.c +--- shadow-4.6/libmisc/setupenv.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/libmisc/setupenv.c 2021-11-03 09:24:05.683172791 +0100 +@@ -219,7 +219,7 @@ void setup_env (struct passwd *info) + static char temp_pw_dir[] = "/"; + + if (!getdef_bool ("DEFAULT_HOME") || chdir ("/") == -1) { +- fprintf (stderr, _("Unable to cd to '%s'\n"), ++ fprintf (shadow_logfd, _("Unable to cd to '%s'\n"), + info->pw_dir); + SYSLOG ((LOG_WARN, + "unable to cd to `%s' for user `%s'\n", +diff -up shadow-4.6/libmisc/user_busy.c.libsubid_not_print_error_messages shadow-4.6/libmisc/user_busy.c +--- shadow-4.6/libmisc/user_busy.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.669172680 +0100 ++++ shadow-4.6/libmisc/user_busy.c 2021-11-03 09:24:05.683172791 +0100 +@@ -96,7 +96,7 @@ static int user_busy_utmp (const char *n + continue; + } + +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: user %s is currently logged in\n"), + Prog, name); + return 1; +@@ -249,7 +249,7 @@ static int user_busy_processes (const ch + #ifdef ENABLE_SUBIDS + sub_uid_close(); + #endif +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: user %s is currently used by process %d\n"), + Prog, name, pid); + return 1; +@@ -272,7 +272,7 @@ static int user_busy_processes (const ch + #ifdef ENABLE_SUBIDS + sub_uid_close(); + #endif +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: user %s is currently used by process %d\n"), + Prog, name, pid); + return 1; +diff -up shadow-4.6/libmisc/xgetXXbyYY.c.libsubid_not_print_error_messages shadow-4.6/libmisc/xgetXXbyYY.c +--- shadow-4.6/libmisc/xgetXXbyYY.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/libmisc/xgetXXbyYY.c 2021-11-03 09:24:05.683172791 +0100 +@@ -74,7 +74,7 @@ + + result = malloc(sizeof(LOOKUP_TYPE)); + if (NULL == result) { +- fprintf (stderr, _("%s: out of memory\n"), ++ fprintf (shadow_logfd, _("%s: out of memory\n"), + "x" STRINGIZE(FUNCTION_NAME)); + exit (13); + } +@@ -84,7 +84,7 @@ + LOOKUP_TYPE *resbuf = NULL; + buffer = (char *)realloc (buffer, length); + if (NULL == buffer) { +- fprintf (stderr, _("%s: out of memory\n"), ++ fprintf (shadow_logfd, _("%s: out of memory\n"), + "x" STRINGIZE(FUNCTION_NAME)); + exit (13); + } +@@ -132,7 +132,7 @@ + if (result) { + result = DUP_FUNCTION(result); + if (NULL == result) { +- fprintf (stderr, _("%s: out of memory\n"), ++ fprintf (shadow_logfd, _("%s: out of memory\n"), + "x" STRINGIZE(FUNCTION_NAME)); + exit (13); + } +diff -up shadow-4.6/libmisc/xmalloc.c.libsubid_not_print_error_messages shadow-4.6/libmisc/xmalloc.c +--- shadow-4.6/libmisc/xmalloc.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/libmisc/xmalloc.c 2021-11-03 09:24:05.683172791 +0100 +@@ -54,7 +54,7 @@ + + ptr = (char *) malloc (size); + if (NULL == ptr) { +- (void) fprintf (stderr, ++ (void) fprintf (shadow_logfd, + _("%s: failed to allocate memory: %s\n"), + Prog, strerror (errno)); + exit (13); +diff -up shadow-4.6/lib/nscd.c.libsubid_not_print_error_messages shadow-4.6/lib/nscd.c +--- shadow-4.6/lib/nscd.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/lib/nscd.c 2021-11-03 09:24:05.683172791 +0100 +@@ -25,13 +25,13 @@ int nscd_flush_cache (const char *servic + + if (run_command (cmd, spawnedArgs, spawnedEnv, &status) != 0) { + /* run_command writes its own more detailed message. */ +- (void) fprintf (stderr, _(MSG_NSCD_FLUSH_CACHE_FAILED), Prog); ++ (void) fprintf (shadow_logfd, _(MSG_NSCD_FLUSH_CACHE_FAILED), Prog); + return -1; + } + + code = WEXITSTATUS (status); + if (!WIFEXITED (status)) { +- (void) fprintf (stderr, ++ (void) fprintf (shadow_logfd, + _("%s: nscd did not terminate normally (signal %d)\n"), + Prog, WTERMSIG (status)); + return -1; +@@ -43,9 +43,9 @@ int nscd_flush_cache (const char *servic + /* nscd is installed, but it isn't active. */ + return 0; + } else if (code != 0) { +- (void) fprintf (stderr, _("%s: nscd exited with status %d\n"), ++ (void) fprintf (shadow_logfd, _("%s: nscd exited with status %d\n"), + Prog, code); +- (void) fprintf (stderr, _(MSG_NSCD_FLUSH_CACHE_FAILED), Prog); ++ (void) fprintf (shadow_logfd, _(MSG_NSCD_FLUSH_CACHE_FAILED), Prog); + return -1; + } + +diff -up shadow-4.6/lib/nss.c.libsubid_not_print_error_messages shadow-4.6/lib/nss.c +--- shadow-4.6/lib/nss.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.678172751 +0100 ++++ shadow-4.6/lib/nss.c 2021-11-03 09:24:05.683172791 +0100 +@@ -56,7 +56,7 @@ void nss_init(char *nsswitch_path) { + // subid: files + nssfp = fopen(nsswitch_path, "r"); + if (!nssfp) { +- fprintf(stderr, "Failed opening %s: %m", nsswitch_path); ++ fprintf(shadow_logfd, "Failed opening %s: %m", nsswitch_path); + atomic_store(&nss_init_completed, true); + return; + } +@@ -82,16 +82,16 @@ void nss_init(char *nsswitch_path) { + goto done; + } + if (strlen(token) > 50) { +- fprintf(stderr, "Subid NSS module name too long (longer than 50 characters): %s\n", token); +- fprintf(stderr, "Using files\n"); ++ fprintf(shadow_logfd, "Subid NSS module name too long (longer than 50 characters): %s\n", token); ++ fprintf(shadow_logfd, "Using files\n"); + subid_nss = NULL; + goto done; + } + snprintf(libname, 64, "libsubid_%s.so", token); + h = dlopen(libname, RTLD_LAZY); + if (!h) { +- fprintf(stderr, "Error opening %s: %s\n", libname, dlerror()); +- fprintf(stderr, "Using files\n"); ++ fprintf(shadow_logfd, "Error opening %s: %s\n", libname, dlerror()); ++ fprintf(shadow_logfd, "Using files\n"); + subid_nss = NULL; + goto done; + } +@@ -102,7 +102,7 @@ void nss_init(char *nsswitch_path) { + } + subid_nss->has_range = dlsym(h, "shadow_subid_has_range"); + if (!subid_nss->has_range) { +- fprintf(stderr, "%s did not provide @has_range@\n", libname); ++ fprintf(shadow_logfd, "%s did not provide @has_range@\n", libname); + dlclose(h); + free(subid_nss); + subid_nss = NULL; +@@ -110,7 +110,7 @@ void nss_init(char *nsswitch_path) { + } + subid_nss->list_owner_ranges = dlsym(h, "shadow_subid_list_owner_ranges"); + if (!subid_nss->list_owner_ranges) { +- fprintf(stderr, "%s did not provide @list_owner_ranges@\n", libname); ++ fprintf(shadow_logfd, "%s did not provide @list_owner_ranges@\n", libname); + dlclose(h); + free(subid_nss); + subid_nss = NULL; +@@ -118,7 +118,7 @@ void nss_init(char *nsswitch_path) { + } + subid_nss->has_any_range = dlsym(h, "shadow_subid_has_any_range"); + if (!subid_nss->has_any_range) { +- fprintf(stderr, "%s did not provide @has_any_range@\n", libname); ++ fprintf(shadow_logfd, "%s did not provide @has_any_range@\n", libname); + dlclose(h); + free(subid_nss); + subid_nss = NULL; +@@ -126,7 +126,7 @@ void nss_init(char *nsswitch_path) { + } + subid_nss->find_subid_owners = dlsym(h, "shadow_subid_find_subid_owners"); + if (!subid_nss->find_subid_owners) { +- fprintf(stderr, "%s did not provide @find_subid_owners@\n", libname); ++ fprintf(shadow_logfd, "%s did not provide @find_subid_owners@\n", libname); + dlclose(h); + free(subid_nss); + subid_nss = NULL; +@@ -135,7 +135,7 @@ void nss_init(char *nsswitch_path) { + subid_nss->handle = h; + goto done; + } +- fprintf(stderr, "No usable subid NSS module found, using files\n"); ++ fprintf(shadow_logfd, "No usable subid NSS module found, using files\n"); + // subid_nss has to be null here, but to ease reviews: + free(subid_nss); + subid_nss = NULL; +diff -up shadow-4.6/lib/prototypes.h.libsubid_not_print_error_messages shadow-4.6/lib/prototypes.h +--- shadow-4.6/lib/prototypes.h.libsubid_not_print_error_messages 2021-11-03 09:24:05.678172751 +0100 ++++ shadow-4.6/lib/prototypes.h 2021-11-03 09:24:05.683172791 +0100 +@@ -59,7 +59,8 @@ + #include "defines.h" + #include "commonio.h" + +-extern /*@observer@*/ const char *Prog; ++extern /*@observer@*/ const char *Prog; /* Program name showed in error messages */ ++extern FILE *shadow_logfd; /* file descripter to which error messages are printed */ + + /* addgrps.c */ + #if defined (HAVE_SETGROUPS) && ! defined (USE_PAM) +diff -up shadow-4.6/lib/selinux.c.libsubid_not_print_error_messages shadow-4.6/lib/selinux.c +diff -up shadow-4.6/lib/semanage.c.libsubid_not_print_error_messages shadow-4.6/lib/semanage.c +--- shadow-4.6/lib/semanage.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.644172481 +0100 ++++ shadow-4.6/lib/semanage.c 2021-11-03 09:24:05.691172854 +0100 +@@ -69,7 +69,7 @@ static void semanage_error_callback (unu + switch (semanage_msg_get_level (handle)) { + case SEMANAGE_MSG_ERR: + case SEMANAGE_MSG_WARN: +- fprintf (stderr, _("[libsemanage]: %s\n"), message); ++ fprintf (shadow_logfd, _("[libsemanage]: %s\n"), message); + break; + case SEMANAGE_MSG_INFO: + /* nop */ +@@ -87,7 +87,7 @@ static semanage_handle_t *semanage_init + + handle = semanage_handle_create (); + if (NULL == handle) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("Cannot create SELinux management handle\n")); + return NULL; + } +@@ -96,26 +96,26 @@ static semanage_handle_t *semanage_init + + ret = semanage_is_managed (handle); + if (ret != 1) { +- fprintf (stderr, _("SELinux policy not managed\n")); ++ fprintf (shadow_logfd, _("SELinux policy not managed\n")); + goto fail; + } + + ret = semanage_access_check (handle); + if (ret < SEMANAGE_CAN_READ) { +- fprintf (stderr, _("Cannot read SELinux policy store\n")); ++ fprintf (shadow_logfd, _("Cannot read SELinux policy store\n")); + goto fail; + } + + ret = semanage_connect (handle); + if (ret != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("Cannot establish SELinux management connection\n")); + goto fail; + } + + ret = semanage_begin_transaction (handle); + if (ret != 0) { +- fprintf (stderr, _("Cannot begin SELinux transaction\n")); ++ fprintf (shadow_logfd, _("Cannot begin SELinux transaction\n")); + goto fail; + } + +@@ -137,7 +137,7 @@ static int semanage_user_mod (semanage_h + + semanage_seuser_query (handle, key, &seuser); + if (NULL == seuser) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("Could not query seuser for %s\n"), login_name); + ret = 1; + goto done; +@@ -146,7 +146,7 @@ static int semanage_user_mod (semanage_h + #if 0 + ret = semanage_seuser_set_mlsrange (handle, seuser, DEFAULT_SERANGE); + if (ret != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("Could not set serange for %s\n"), login_name); + ret = 1; + goto done; +@@ -155,7 +155,7 @@ static int semanage_user_mod (semanage_h + + ret = semanage_seuser_set_sename (handle, seuser, seuser_name); + if (ret != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("Could not set sename for %s\n"), + login_name); + ret = 1; +@@ -164,7 +164,7 @@ static int semanage_user_mod (semanage_h + + ret = semanage_seuser_modify_local (handle, key, seuser); + if (ret != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("Could not modify login mapping for %s\n"), + login_name); + ret = 1; +@@ -188,7 +188,7 @@ static int semanage_user_add (semanage_h + + ret = semanage_seuser_create (handle, &seuser); + if (ret != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("Cannot create SELinux login mapping for %s\n"), + login_name); + ret = 1; +@@ -197,7 +197,7 @@ static int semanage_user_add (semanage_h + + ret = semanage_seuser_set_name (handle, seuser, login_name); + if (ret != 0) { +- fprintf (stderr, _("Could not set name for %s\n"), login_name); ++ fprintf (shadow_logfd, _("Could not set name for %s\n"), login_name); + ret = 1; + goto done; + } +@@ -205,7 +205,7 @@ static int semanage_user_add (semanage_h + #if 0 + ret = semanage_seuser_set_mlsrange (handle, seuser, DEFAULT_SERANGE); + if (ret != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("Could not set serange for %s\n"), + login_name); + ret = 1; +@@ -215,7 +215,7 @@ static int semanage_user_add (semanage_h + + ret = semanage_seuser_set_sename (handle, seuser, seuser_name); + if (ret != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("Could not set SELinux user for %s\n"), + login_name); + ret = 1; +@@ -224,7 +224,7 @@ static int semanage_user_add (semanage_h + + ret = semanage_seuser_modify_local (handle, key, seuser); + if (ret != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("Could not add login mapping for %s\n"), + login_name); + ret = 1; +@@ -252,21 +252,21 @@ int set_seuser (const char *login_name, + + handle = semanage_init (); + if (NULL == handle) { +- fprintf (stderr, _("Cannot init SELinux management\n")); ++ fprintf (shadow_logfd, _("Cannot init SELinux management\n")); + ret = 1; + goto done; + } + + ret = semanage_seuser_key_create (handle, login_name, &key); + if (ret != 0) { +- fprintf (stderr, _("Cannot create SELinux user key\n")); ++ fprintf (shadow_logfd, _("Cannot create SELinux user key\n")); + ret = 1; + goto done; + } + + ret = semanage_seuser_exists (handle, key, &seuser_exists); + if (ret < 0) { +- fprintf (stderr, _("Cannot verify the SELinux user\n")); ++ fprintf (shadow_logfd, _("Cannot verify the SELinux user\n")); + ret = 1; + goto done; + } +@@ -274,7 +274,7 @@ int set_seuser (const char *login_name, + if (0 != seuser_exists) { + ret = semanage_user_mod (handle, key, login_name, seuser_name); + if (ret != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("Cannot modify SELinux user mapping\n")); + ret = 1; + goto done; +@@ -282,7 +282,7 @@ int set_seuser (const char *login_name, + } else { + ret = semanage_user_add (handle, key, login_name, seuser_name); + if (ret != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("Cannot add SELinux user mapping\n")); + ret = 1; + goto done; +@@ -291,7 +291,7 @@ int set_seuser (const char *login_name, + + ret = semanage_commit (handle); + if (ret < 0) { +- fprintf (stderr, _("Cannot commit SELinux transaction\n")); ++ fprintf (shadow_logfd, _("Cannot commit SELinux transaction\n")); + ret = 1; + goto done; + } +@@ -317,27 +317,27 @@ int del_seuser (const char *login_name) + + handle = semanage_init (); + if (NULL == handle) { +- fprintf (stderr, _("Cannot init SELinux management\n")); ++ fprintf (shadow_logfd, _("Cannot init SELinux management\n")); + ret = 1; + goto done; + } + + ret = semanage_seuser_key_create (handle, login_name, &key); + if (ret != 0) { +- fprintf (stderr, _("Cannot create SELinux user key\n")); ++ fprintf (shadow_logfd, _("Cannot create SELinux user key\n")); + ret = 1; + goto done; + } + + ret = semanage_seuser_exists (handle, key, &exists); + if (ret < 0) { +- fprintf (stderr, _("Cannot verify the SELinux user\n")); ++ fprintf (shadow_logfd, _("Cannot verify the SELinux user\n")); + ret = 1; + goto done; + } + + if (0 == exists) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("Login mapping for %s is not defined, OK if default mapping was used\n"), + login_name); + ret = 0; /* probably default mapping */ +@@ -346,13 +346,13 @@ int del_seuser (const char *login_name) + + ret = semanage_seuser_exists_local (handle, key, &exists); + if (ret < 0) { +- fprintf (stderr, _("Cannot verify the SELinux user\n")); ++ fprintf (shadow_logfd, _("Cannot verify the SELinux user\n")); + ret = 1; + goto done; + } + + if (0 == exists) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("Login mapping for %s is defined in policy, cannot be deleted\n"), + login_name); + ret = 0; /* Login mapping defined in policy can't be deleted */ +@@ -361,7 +361,7 @@ int del_seuser (const char *login_name) + + ret = semanage_seuser_del_local (handle, key); + if (ret != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("Could not delete login mapping for %s"), + login_name); + ret = 1; +@@ -370,7 +370,7 @@ int del_seuser (const char *login_name) + + ret = semanage_commit (handle); + if (ret < 0) { +- fprintf (stderr, _("Cannot commit SELinux transaction\n")); ++ fprintf (shadow_logfd, _("Cannot commit SELinux transaction\n")); + ret = 1; + goto done; + } +diff -up shadow-4.6/lib/spawn.c.libsubid_not_print_error_messages shadow-4.6/lib/spawn.c +--- shadow-4.6/lib/spawn.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.660172608 +0100 ++++ shadow-4.6/lib/spawn.c 2021-11-03 09:24:05.692172863 +0100 +@@ -48,7 +48,7 @@ int run_command (const char *cmd, const + } + + (void) fflush (stdout); +- (void) fflush (stderr); ++ (void) fflush (shadow_logfd); + + pid = fork (); + if (0 == pid) { +@@ -57,11 +57,11 @@ int run_command (const char *cmd, const + if (ENOENT == errno) { + exit (E_CMD_NOTFOUND); + } +- fprintf (stderr, "%s: cannot execute %s: %s\n", ++ fprintf (shadow_logfd, "%s: cannot execute %s: %s\n", + Prog, cmd, strerror (errno)); + exit (E_CMD_NOEXEC); + } else if ((pid_t)-1 == pid) { +- fprintf (stderr, "%s: cannot execute %s: %s\n", ++ fprintf (shadow_logfd, "%s: cannot execute %s: %s\n", + Prog, cmd, strerror (errno)); + return -1; + } +@@ -72,7 +72,7 @@ int run_command (const char *cmd, const + || ((pid_t)-1 != wpid && wpid != pid)); + + if ((pid_t)-1 == wpid) { +- fprintf (stderr, "%s: waitpid (status: %d): %s\n", ++ fprintf (shadow_logfd, "%s: waitpid (status: %d): %s\n", + Prog, *status, strerror (errno)); + return -1; + } +diff -up shadow-4.6/libsubid/api.c.libsubid_not_print_error_messages shadow-4.6/libsubid/api.c +--- shadow-4.6/libsubid/api.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.678172751 +0100 ++++ shadow-4.6/libsubid/api.c 2021-11-03 09:24:05.692172863 +0100 +@@ -32,12 +32,39 @@ + #include + #include + #include ++#include + #include + #include + #include "subordinateio.h" + #include "idmapping.h" + #include "subid.h" + ++const char *Prog = "(libsubid)"; ++extern FILE * shadow_logfd; ++ ++bool libsubid_init(const char *progname, FILE * logfd) ++{ ++ if (progname) { ++ progname = strdup(progname); ++ if (progname) ++ Prog = progname; ++ else ++ fprintf(stderr, "Out of memory"); ++ } ++ ++ if (logfd) { ++ shadow_logfd = logfd; ++ return true; ++ } ++ shadow_logfd = fopen("/dev/null", "w"); ++ if (!shadow_logfd) { ++ fprintf(stderr, "ERROR opening /dev/null for error messages. Using stderr."); ++ shadow_logfd = stderr; ++ return false; ++ } ++ return true; ++} ++ + static + int get_subid_ranges(const char *owner, enum subid_type id_type, struct subordinate_range ***ranges) + { +diff -up shadow-4.6/libsubid/subid.h.libsubid_not_print_error_messages shadow-4.6/libsubid/subid.h +--- shadow-4.6/libsubid/subid.h.libsubid_not_print_error_messages 2021-11-03 09:24:05.678172751 +0100 ++++ shadow-4.6/libsubid/subid.h 2021-11-03 09:24:05.692172863 +0100 +@@ -22,6 +22,22 @@ enum subid_status { + }; + + /* ++ * libsubid_init: initialize libsubid ++ * ++ * @progname: Name to display as program. If NULL, then "(libsubid)" will be ++ * shown in error messages. ++ * @logfd: Open file pointer to pass error messages to. If NULL, then ++ * /dev/null will be opened and messages will be sent there. The ++ * default if libsubid_init() is not called is stderr (2). ++ * ++ * This function does not need to be called. If not called, then the defaults ++ * will be used. ++ * ++ * Returns false if an error occurred. ++ */ ++bool libsubid_init(const char *progname, FILE *logfd); ++ ++/* + * get_subuid_ranges: return a list of UID ranges for a user + * + * @owner: username being queried +diff -up shadow-4.6/lib/tcbfuncs.c.libsubid_not_print_error_messages shadow-4.6/lib/tcbfuncs.c +--- shadow-4.6/lib/tcbfuncs.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/lib/tcbfuncs.c 2021-11-03 09:24:05.693172870 +0100 +@@ -72,8 +72,8 @@ shadowtcb_status shadowtcb_gain_priv (vo + * to exit soon. + */ + #define OUT_OF_MEMORY do { \ +- fprintf (stderr, _("%s: out of memory\n"), Prog); \ +- (void) fflush (stderr); \ ++ fprintf (shadow_logfd, _("%s: out of memory\n"), Prog); \ ++ (void) fflush (shadow_logfd); \ + } while (false) + + /* Returns user's tcb directory path relative to TCB_DIR. */ +@@ -116,7 +116,7 @@ static /*@null@*/ char *shadowtcb_path_r + return NULL; + } + if (lstat (path, &st) != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Cannot stat %s: %s\n"), + Prog, path, strerror (errno)); + free (path); +@@ -132,7 +132,7 @@ static /*@null@*/ char *shadowtcb_path_r + return rval; + } + if (!S_ISLNK (st.st_mode)) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: %s is neither a directory, nor a symlink.\n"), + Prog, path); + free (path); +@@ -140,7 +140,7 @@ static /*@null@*/ char *shadowtcb_path_r + } + ret = readlink (path, link, sizeof (link) - 1); + if (-1 == ret) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Cannot read symbolic link %s: %s\n"), + Prog, path, strerror (errno)); + free (path); +@@ -149,7 +149,7 @@ static /*@null@*/ char *shadowtcb_path_r + free (path); + if ((size_t)ret >= sizeof(link) - 1) { + link[sizeof(link) - 1] = '\0'; +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Suspiciously long symlink: %s\n"), + Prog, link); + return NULL; +@@ -207,7 +207,7 @@ static shadowtcb_status mkdir_leading (c + } + ptr = path; + if (stat (TCB_DIR, &st) != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Cannot stat %s: %s\n"), + Prog, TCB_DIR, strerror (errno)); + goto out_free_path; +@@ -219,19 +219,19 @@ static shadowtcb_status mkdir_leading (c + return SHADOWTCB_FAILURE; + } + if ((mkdir (dir, 0700) != 0) && (errno != EEXIST)) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Cannot create directory %s: %s\n"), + Prog, dir, strerror (errno)); + goto out_free_dir; + } + if (chown (dir, 0, st.st_gid) != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Cannot change owner of %s: %s\n"), + Prog, dir, strerror (errno)); + goto out_free_dir; + } + if (chmod (dir, 0711) != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Cannot change mode of %s: %s\n"), + Prog, dir, strerror (errno)); + goto out_free_dir; +@@ -261,7 +261,7 @@ static shadowtcb_status unlink_suffs (co + return SHADOWTCB_FAILURE; + } + if ((unlink (tmp) != 0) && (errno != ENOENT)) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: unlink: %s: %s\n"), + Prog, tmp, strerror (errno)); + free (tmp); +@@ -286,7 +286,7 @@ static shadowtcb_status rmdir_leading (c + } + if (rmdir (dir) != 0) { + if (errno != ENOTEMPTY) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Cannot remove directory %s: %s\n"), + Prog, dir, strerror (errno)); + ret = SHADOWTCB_FAILURE; +@@ -315,7 +315,7 @@ static shadowtcb_status move_dir (const + goto out_free_nomem; + } + if (stat (olddir, &oldmode) != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Cannot stat %s: %s\n"), + Prog, olddir, strerror (errno)); + goto out_free; +@@ -342,7 +342,7 @@ static shadowtcb_status move_dir (const + goto out_free; + } + if (rename (real_old_dir, real_new_dir) != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Cannot rename %s to %s: %s\n"), + Prog, real_old_dir, real_new_dir, strerror (errno)); + goto out_free; +@@ -351,7 +351,7 @@ static shadowtcb_status move_dir (const + goto out_free; + } + if ((unlink (olddir) != 0) && (errno != ENOENT)) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Cannot remove %s: %s\n"), + Prog, olddir, strerror (errno)); + goto out_free; +@@ -365,7 +365,7 @@ static shadowtcb_status move_dir (const + } + if ( (strcmp (real_new_dir, newdir) != 0) + && (symlink (real_new_dir_rel, newdir) != 0)) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Cannot create symbolic link %s: %s\n"), + Prog, real_new_dir_rel, strerror (errno)); + goto out_free; +@@ -464,37 +464,37 @@ shadowtcb_status shadowtcb_move (/*@NULL + return SHADOWTCB_FAILURE; + } + if (stat (tcbdir, &dirmode) != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Cannot stat %s: %s\n"), + Prog, tcbdir, strerror (errno)); + goto out_free; + } + if (chown (tcbdir, 0, 0) != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Cannot change owners of %s: %s\n"), + Prog, tcbdir, strerror (errno)); + goto out_free; + } + if (chmod (tcbdir, 0700) != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Cannot change mode of %s: %s\n"), + Prog, tcbdir, strerror (errno)); + goto out_free; + } + if (lstat (shadow, &filemode) != 0) { + if (errno != ENOENT) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Cannot lstat %s: %s\n"), + Prog, shadow, strerror (errno)); + goto out_free; + } +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Warning, user %s has no tcb shadow file.\n"), + Prog, user_newname); + } else { + if (!S_ISREG (filemode.st_mode) || + filemode.st_nlink != 1) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Emergency: %s's tcb shadow is not a " + "regular file with st_nlink=1.\n" + "The account is left locked.\n"), +@@ -502,13 +502,13 @@ shadowtcb_status shadowtcb_move (/*@NULL + goto out_free; + } + if (chown (shadow, user_newid, filemode.st_gid) != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Cannot change owner of %s: %s\n"), + Prog, shadow, strerror (errno)); + goto out_free; + } + if (chmod (shadow, filemode.st_mode & 07777) != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Cannot change mode of %s: %s\n"), + Prog, shadow, strerror (errno)); + goto out_free; +@@ -518,7 +518,7 @@ shadowtcb_status shadowtcb_move (/*@NULL + goto out_free; + } + if (chown (tcbdir, user_newid, dirmode.st_gid) != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Cannot change owner of %s: %s\n"), + Prog, tcbdir, strerror (errno)); + goto out_free; +@@ -543,7 +543,7 @@ shadowtcb_status shadowtcb_create (const + return SHADOWTCB_SUCCESS; + } + if (stat (TCB_DIR, &tcbdir_stat) != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Cannot stat %s: %s\n"), + Prog, TCB_DIR, strerror (errno)); + return SHADOWTCB_FAILURE; +@@ -563,39 +563,39 @@ shadowtcb_status shadowtcb_create (const + return SHADOWTCB_FAILURE; + } + if (mkdir (dir, 0700) != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: mkdir: %s: %s\n"), + Prog, dir, strerror (errno)); + goto out_free; + } + fd = open (shadow, O_RDWR | O_CREAT | O_TRUNC, 0600); + if (fd < 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Cannot open %s: %s\n"), + Prog, shadow, strerror (errno)); + goto out_free; + } + close (fd); + if (chown (shadow, 0, authgid) != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Cannot change owner of %s: %s\n"), + Prog, shadow, strerror (errno)); + goto out_free; + } + if (chmod (shadow, (mode_t) ((authgid == shadowgid) ? 0600 : 0640)) != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Cannot change mode of %s: %s\n"), + Prog, shadow, strerror (errno)); + goto out_free; + } + if (chown (dir, 0, authgid) != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Cannot change owner of %s: %s\n"), + Prog, dir, strerror (errno)); + goto out_free; + } + if (chmod (dir, (mode_t) ((authgid == shadowgid) ? 02700 : 02710)) != 0) { +- fprintf (stderr, ++ fprintf (shadow_logfd, + _("%s: Cannot change mode of %s: %s\n"), + Prog, dir, strerror (errno)); + goto out_free; +diff -up shadow-4.6/src/chage.c.libsubid_not_print_error_messages shadow-4.6/src/chage.c +--- shadow-4.6/src/chage.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.655172568 +0100 ++++ shadow-4.6/src/chage.c 2021-11-03 09:24:05.694172878 +0100 +@@ -66,6 +66,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + + static bool + dflg = false, /* set last password change date */ +@@ -806,6 +807,7 @@ int main (int argc, char **argv) + * Get the program name so that error messages can use it. + */ + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + sanitize_env (); + (void) setlocale (LC_ALL, ""); +diff -up shadow-4.6/src/check_subid_range.c.libsubid_not_print_error_messages shadow-4.6/src/check_subid_range.c +--- shadow-4.6/src/check_subid_range.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.678172751 +0100 ++++ shadow-4.6/src/check_subid_range.c 2021-11-03 09:24:05.694172878 +0100 +@@ -18,6 +18,7 @@ + #include "idmapping.h" + + const char *Prog; ++FILE *shadow_logfd = NULL; + + int main(int argc, char **argv) + { +@@ -25,6 +26,7 @@ int main(int argc, char **argv) + unsigned long start, count; + bool check_uids; + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + if (argc != 5) + exit(1); +diff -up shadow-4.6/src/chfn.c.libsubid_not_print_error_messages shadow-4.6/src/chfn.c +--- shadow-4.6/src/chfn.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.662172624 +0100 ++++ shadow-4.6/src/chfn.c 2021-11-03 09:24:05.695172886 +0100 +@@ -61,6 +61,7 @@ + * Global variables. + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + static char fullnm[BUFSIZ]; + static char roomno[BUFSIZ]; + static char workph[BUFSIZ]; +@@ -639,6 +640,7 @@ int main (int argc, char **argv) + * prefix to most error messages. + */ + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + sanitize_env (); + (void) setlocale (LC_ALL, ""); +diff -up shadow-4.6/src/chgpasswd.c.libsubid_not_print_error_messages shadow-4.6/src/chgpasswd.c +--- shadow-4.6/src/chgpasswd.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.662172624 +0100 ++++ shadow-4.6/src/chgpasswd.c 2021-11-03 09:32:53.937617545 +0100 +@@ -66,6 +66,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + static bool eflg = false; + static bool md5flg = false; + #ifdef USE_SHA_CRYPT +@@ -466,6 +467,7 @@ int main (int argc, char **argv) + int line = 0; + + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + (void) setlocale (LC_ALL, ""); + (void) bindtextdomain (PACKAGE, LOCALEDIR); +diff -up shadow-4.6/src/chpasswd.c.libsubid_not_print_error_messages shadow-4.6/src/chpasswd.c +--- shadow-4.6/src/chpasswd.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.662172624 +0100 ++++ shadow-4.6/src/chpasswd.c 2021-11-03 09:33:19.029832153 +0100 +@@ -63,6 +63,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + static bool eflg = false; + static bool md5flg = false; + #ifdef USE_SHA_CRYPT +@@ -453,6 +454,7 @@ int main (int argc, char **argv) + int line = 0; + + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + (void) setlocale (LC_ALL, ""); + (void) bindtextdomain (PACKAGE, LOCALEDIR); +diff -up shadow-4.6/src/chsh.c.libsubid_not_print_error_messages shadow-4.6/src/chsh.c +--- shadow-4.6/src/chsh.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.662172624 +0100 ++++ shadow-4.6/src/chsh.c 2021-11-03 09:24:05.697172902 +0100 +@@ -63,6 +63,7 @@ + * Global variables + */ + const char *Prog; /* Program name */ ++FILE *shadow_logfd = NULL; + static bool amroot; /* Real UID is root */ + static char loginsh[BUFSIZ]; /* Name of new login shell */ + /* command line options */ +@@ -446,6 +447,7 @@ int main (int argc, char **argv) + * most error messages. + */ + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + (void) setlocale (LC_ALL, ""); + (void) bindtextdomain (PACKAGE, LOCALEDIR); +diff -up shadow-4.6/src/expiry.c.libsubid_not_print_error_messages shadow-4.6/src/expiry.c +--- shadow-4.6/src/expiry.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/src/expiry.c 2021-11-03 09:24:05.698172910 +0100 +@@ -46,6 +46,7 @@ + + /* Global variables */ + const char *Prog; ++FILE *shadow_logfd = NULL; + static bool cflg = false; + + /* local function prototypes */ +@@ -144,6 +145,7 @@ int main (int argc, char **argv) + struct spwd *spwd; + + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + sanitize_env (); + +diff -up shadow-4.6/src/faillog.c.libsubid_not_print_error_messages shadow-4.6/src/faillog.c +--- shadow-4.6/src/faillog.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.655172568 +0100 ++++ shadow-4.6/src/faillog.c 2021-11-03 09:24:05.698172910 +0100 +@@ -62,6 +62,7 @@ static void reset (void); + * Global variables + */ + const char *Prog; /* Program name */ ++FILE *shadow_logfd = NULL; + static FILE *fail; /* failure file stream */ + static time_t seconds; /* that number of days in seconds */ + static unsigned long umin; /* if uflg and has_umin, only display users with uid >= umin */ +@@ -573,6 +574,7 @@ int main (int argc, char **argv) + * most error messages. + */ + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + (void) setlocale (LC_ALL, ""); + (void) bindtextdomain (PACKAGE, LOCALEDIR); +diff -up shadow-4.6/src/free_subid_range.c.libsubid_not_print_error_messages shadow-4.6/src/free_subid_range.c +--- shadow-4.6/src/free_subid_range.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.678172751 +0100 ++++ shadow-4.6/src/free_subid_range.c 2021-11-03 09:24:05.698172910 +0100 +@@ -7,6 +7,7 @@ + /* Test program for the subid freeing routine */ + + const char *Prog; ++FILE *shadow_logfd = NULL; + + void usage(void) + { +@@ -23,6 +24,7 @@ int main(int argc, char *argv[]) + bool group = false; // get subuids by default + + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + while ((c = getopt(argc, argv, "g")) != EOF) { + switch(c) { + case 'g': group = true; break; +diff -up shadow-4.6/src/get_subid_owners.c.libsubid_not_print_error_messages shadow-4.6/src/get_subid_owners.c +--- shadow-4.6/src/get_subid_owners.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.678172751 +0100 ++++ shadow-4.6/src/get_subid_owners.c 2021-11-03 09:24:05.699172918 +0100 +@@ -4,6 +4,7 @@ + #include "prototypes.h" + + const char *Prog; ++FILE *shadow_logfd = NULL; + + void usage(void) + { +@@ -19,6 +20,7 @@ int main(int argc, char *argv[]) + uid_t *uids; + + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + if (argc < 2) { + usage(); + } +diff -up shadow-4.6/src/gpasswd.c.libsubid_not_print_error_messages shadow-4.6/src/gpasswd.c +--- shadow-4.6/src/gpasswd.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.662172624 +0100 ++++ shadow-4.6/src/gpasswd.c 2021-11-03 09:24:05.699172918 +0100 +@@ -58,6 +58,7 @@ + */ + /* The name of this command, as it is invoked */ + const char *Prog; ++FILE *shadow_logfd = NULL; + + #ifdef SHADOWGRP + /* Indicate if shadow groups are enabled on the system +@@ -926,6 +927,7 @@ int main (int argc, char **argv) + */ + bywho = getuid (); + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + OPENLOG ("gpasswd"); + setbuf (stdout, NULL); +diff -up shadow-4.6/src/groupadd.c.libsubid_not_print_error_messages shadow-4.6/src/groupadd.c +--- shadow-4.6/src/groupadd.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.662172624 +0100 ++++ shadow-4.6/src/groupadd.c 2021-11-03 09:24:05.700172926 +0100 +@@ -72,6 +72,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + + static /*@null@*/char *group_name; + static gid_t group_id; +@@ -582,6 +583,7 @@ int main (int argc, char **argv) + * Get my name so that I can use it to report errors. + */ + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + (void) setlocale (LC_ALL, ""); + (void) bindtextdomain (PACKAGE, LOCALEDIR); +diff -up shadow-4.6/src/groupdel.c.libsubid_not_print_error_messages shadow-4.6/src/groupdel.c +--- shadow-4.6/src/groupdel.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.662172624 +0100 ++++ shadow-4.6/src/groupdel.c 2021-11-03 09:24:05.700172926 +0100 +@@ -58,6 +58,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + + static char *group_name; + static gid_t group_id = -1; +@@ -377,6 +378,7 @@ int main (int argc, char **argv) + * Get my name so that I can use it to report errors. + */ + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + (void) setlocale (LC_ALL, ""); + (void) bindtextdomain (PACKAGE, LOCALEDIR); +diff -up shadow-4.6/src/groupmems.c.libsubid_not_print_error_messages shadow-4.6/src/groupmems.c +--- shadow-4.6/src/groupmems.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/src/groupmems.c 2021-11-03 09:24:05.701172934 +0100 +@@ -65,6 +65,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + + static char *adduser = NULL; + static char *deluser = NULL; +@@ -595,6 +596,7 @@ int main (int argc, char **argv) + * Get my name so that I can use it to report errors. + */ + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + (void) setlocale (LC_ALL, ""); + (void) bindtextdomain (PACKAGE, LOCALEDIR); +diff -up shadow-4.6/src/groupmod.c.libsubid_not_print_error_messages shadow-4.6/src/groupmod.c +--- shadow-4.6/src/groupmod.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.662172624 +0100 ++++ shadow-4.6/src/groupmod.c 2021-11-03 09:24:05.702172942 +0100 +@@ -76,6 +76,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + + #ifdef SHADOWGRP + static bool is_shadow_grp; +@@ -799,6 +800,7 @@ int main (int argc, char **argv) + * Get my name so that I can use it to report errors. + */ + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + (void) setlocale (LC_ALL, ""); + (void) bindtextdomain (PACKAGE, LOCALEDIR); +diff -up shadow-4.6/src/groups.c.libsubid_not_print_error_messages shadow-4.6/src/groups.c +--- shadow-4.6/src/groups.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/src/groups.c 2021-11-03 09:24:05.702172942 +0100 +@@ -43,6 +43,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + + /* local function prototypes */ + static void print_groups (const char *member); +@@ -126,6 +127,7 @@ int main (int argc, char **argv) + * Get the program name so that error messages can use it. + */ + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + if (argc == 1) { + +diff -up shadow-4.6/src/grpck.c.libsubid_not_print_error_messages shadow-4.6/src/grpck.c +--- shadow-4.6/src/grpck.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.662172624 +0100 ++++ shadow-4.6/src/grpck.c 2021-11-03 09:24:05.703172950 +0100 +@@ -68,6 +68,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + + static const char *grp_file = GROUP_FILE; + static bool use_system_grp_file = true; +@@ -836,6 +837,7 @@ int main (int argc, char **argv) + * Get my name so that I can use it to report errors. + */ + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + (void) setlocale (LC_ALL, ""); + (void) bindtextdomain (PACKAGE, LOCALEDIR); +diff -up shadow-4.6/src/grpconv.c.libsubid_not_print_error_messages shadow-4.6/src/grpconv.c +--- shadow-4.6/src/grpconv.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.663172632 +0100 ++++ shadow-4.6/src/grpconv.c 2021-11-03 09:24:05.703172950 +0100 +@@ -59,6 +59,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + + static bool gr_locked = false; + static bool sgr_locked = false; +@@ -146,6 +147,7 @@ int main (int argc, char **argv) + struct sgrp sgent; + + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + (void) setlocale (LC_ALL, ""); + (void) bindtextdomain (PACKAGE, LOCALEDIR); +diff -up shadow-4.6/src/grpunconv.c.libsubid_not_print_error_messages shadow-4.6/src/grpunconv.c +--- shadow-4.6/src/grpunconv.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.663172632 +0100 ++++ shadow-4.6/src/grpunconv.c 2021-11-03 09:24:05.704172958 +0100 +@@ -59,6 +59,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + + static bool gr_locked = false; + static bool sgr_locked = false; +@@ -145,6 +146,7 @@ int main (int argc, char **argv) + const struct sgrp *sg; + + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + (void) setlocale (LC_ALL, ""); + (void) bindtextdomain (PACKAGE, LOCALEDIR); +diff -up shadow-4.6/src/lastlog.c.libsubid_not_print_error_messages shadow-4.6/src/lastlog.c +--- shadow-4.6/src/lastlog.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.655172568 +0100 ++++ shadow-4.6/src/lastlog.c 2021-11-03 09:24:05.704172958 +0100 +@@ -58,6 +58,7 @@ + * Global variables + */ + const char *Prog; /* Program name */ ++FILE *shadow_logfd = NULL; + static FILE *lastlogfile; /* lastlog file stream */ + static unsigned long umin; /* if uflg and has_umin, only display users with uid >= umin */ + static bool has_umin = false; +@@ -283,6 +284,7 @@ int main (int argc, char **argv) + * most error messages. + */ + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + (void) setlocale (LC_ALL, ""); + (void) bindtextdomain (PACKAGE, LOCALEDIR); +diff -up shadow-4.6/src/list_subid_ranges.c.libsubid_not_print_error_messages shadow-4.6/src/list_subid_ranges.c +--- shadow-4.6/src/list_subid_ranges.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.679172759 +0100 ++++ shadow-4.6/src/list_subid_ranges.c 2021-11-03 09:24:05.704172958 +0100 +@@ -4,6 +4,7 @@ + #include "prototypes.h" + + const char *Prog; ++FILE *shadow_logfd = NULL; + + void usage(void) + { +@@ -19,6 +20,7 @@ int main(int argc, char *argv[]) + struct subordinate_range **ranges; + + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + if (argc < 2) { + usage(); + } +diff -up shadow-4.6/src/login.c.libsubid_not_print_error_messages shadow-4.6/src/login.c +--- shadow-4.6/src/login.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/src/login.c 2021-11-03 09:24:05.705172966 +0100 +@@ -83,6 +83,7 @@ static pam_handle_t *pamh = NULL; + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + + static const char *hostname = ""; + static /*@null@*/ /*@only@*/char *username = NULL; +@@ -562,6 +563,7 @@ int main (int argc, char **argv) + + amroot = (getuid () == 0); + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + if (geteuid() != 0) { + fprintf (stderr, _("%s: Cannot possibly work without effective root\n"), Prog); +diff -up shadow-4.6/src/logoutd.c.libsubid_not_print_error_messages shadow-4.6/src/logoutd.c +--- shadow-4.6/src/logoutd.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/src/logoutd.c 2021-11-03 09:24:05.706172974 +0100 +@@ -44,6 +44,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + + #ifndef DEFAULT_HUP_MESG + #define DEFAULT_HUP_MESG _("login time exceeded\n\n") +@@ -187,6 +188,7 @@ int main (int argc, char **argv) + * Start syslogging everything + */ + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + OPENLOG ("logoutd"); + +diff -up shadow-4.6/src/newgidmap.c.libsubid_not_print_error_messages shadow-4.6/src/newgidmap.c +--- shadow-4.6/src/newgidmap.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/src/newgidmap.c 2021-11-03 09:24:05.706172974 +0100 +@@ -45,6 +45,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + + + static bool verify_range(struct passwd *pw, struct map_range *range, bool *allow_setgroups) +@@ -175,6 +176,7 @@ int main(int argc, char **argv) + bool allow_setgroups = false; + + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + /* + * The valid syntax are +diff -up shadow-4.6/src/newgrp.c.libsubid_not_print_error_messages shadow-4.6/src/newgrp.c +--- shadow-4.6/src/newgrp.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.650172528 +0100 ++++ shadow-4.6/src/newgrp.c 2021-11-03 09:24:05.707172982 +0100 +@@ -49,6 +49,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + + extern char **newenvp; + extern char **environ; +@@ -443,6 +444,7 @@ int main (int argc, char **argv) + * don't need to re-exec anything. -- JWP + */ + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + is_newgrp = (strcmp (Prog, "newgrp") == 0); + OPENLOG (is_newgrp ? "newgrp" : "sg"); + gid = getgid (); +diff -up shadow-4.6/src/new_subid_range.c.libsubid_not_print_error_messages shadow-4.6/src/new_subid_range.c +--- shadow-4.6/src/new_subid_range.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.679172759 +0100 ++++ shadow-4.6/src/new_subid_range.c 2021-11-03 09:24:05.707172982 +0100 +@@ -7,6 +7,7 @@ + /* Test program for the subid creation routine */ + + const char *Prog; ++FILE *shadow_logfd = NULL; + + void usage(void) + { +@@ -26,6 +27,7 @@ int main(int argc, char *argv[]) + bool ok; + + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + while ((c = getopt(argc, argv, "gn")) != EOF) { + switch(c) { + case 'n': makenew = true; break; +diff -up shadow-4.6/src/newuidmap.c.libsubid_not_print_error_messages shadow-4.6/src/newuidmap.c +--- shadow-4.6/src/newuidmap.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/src/newuidmap.c 2021-11-03 09:24:05.707172982 +0100 +@@ -45,6 +45,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + + static bool verify_range(struct passwd *pw, struct map_range *range) + { +@@ -105,6 +106,7 @@ int main(int argc, char **argv) + int written; + + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + /* + * The valid syntax are +diff -up shadow-4.6/src/newusers.c.libsubid_not_print_error_messages shadow-4.6/src/newusers.c +--- shadow-4.6/src/newusers.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.670172687 +0100 ++++ shadow-4.6/src/newusers.c 2021-11-03 09:24:05.708172990 +0100 +@@ -75,6 +75,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + + static bool rflg = false; /* create a system account */ + #ifndef USE_PAM +@@ -970,6 +971,7 @@ int main (int argc, char **argv) + #endif /* USE_PAM */ + + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + (void) setlocale (LC_ALL, ""); + (void) bindtextdomain (PACKAGE, LOCALEDIR); +diff -up shadow-4.6/src/passwd.c.libsubid_not_print_error_messages shadow-4.6/src/passwd.c +--- shadow-4.6/src/passwd.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.663172632 +0100 ++++ shadow-4.6/src/passwd.c 2021-11-03 09:24:05.709172998 +0100 +@@ -72,6 +72,7 @@ + * Global variables + */ + const char *Prog; /* Program name */ ++FILE *shadow_logfd = NULL; + + static char *name; /* The name of user whose password is being changed */ + static char *myname; /* The current user's name */ +@@ -808,6 +809,7 @@ int main (int argc, char **argv) + * most error messages. + */ + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + (void) setlocale (LC_ALL, ""); + (void) bindtextdomain (PACKAGE, LOCALEDIR); +diff -up shadow-4.6/src/pwck.c.libsubid_not_print_error_messages shadow-4.6/src/pwck.c +--- shadow-4.6/src/pwck.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.663172632 +0100 ++++ shadow-4.6/src/pwck.c 2021-11-03 09:24:05.709172998 +0100 +@@ -70,6 +70,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + + static bool use_system_pw_file = true; + static bool use_system_spw_file = true; +diff -up shadow-4.6/src/pwconv.c.libsubid_not_print_error_messages shadow-4.6/src/pwconv.c +--- shadow-4.6/src/pwconv.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.663172632 +0100 ++++ shadow-4.6/src/pwconv.c 2021-11-03 09:24:05.709172998 +0100 +@@ -89,6 +89,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + + static bool spw_locked = false; + static bool pw_locked = false; +@@ -176,6 +177,7 @@ int main (int argc, char **argv) + struct spwd spent; + + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + (void) setlocale (LC_ALL, ""); + (void) bindtextdomain (PACKAGE, LOCALEDIR); +diff -up shadow-4.6/src/pwunconv.c.libsubid_not_print_error_messages shadow-4.6/src/pwunconv.c +--- shadow-4.6/src/pwunconv.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.663172632 +0100 ++++ shadow-4.6/src/pwunconv.c 2021-11-03 09:24:05.710173006 +0100 +@@ -53,6 +53,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + + static bool spw_locked = false; + static bool pw_locked = false; +@@ -137,6 +138,7 @@ int main (int argc, char **argv) + const struct spwd *spwd; + + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + (void) setlocale (LC_ALL, ""); + (void) bindtextdomain (PACKAGE, LOCALEDIR); +diff -up shadow-4.6/src/su.c.libsubid_not_print_error_messages shadow-4.6/src/su.c +--- shadow-4.6/src/su.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/src/su.c 2021-11-03 09:24:05.710173006 +0100 +@@ -82,6 +82,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + static /*@observer@*/const char *caller_tty = NULL; /* Name of tty SU is run from */ + static bool caller_is_root = false; + static uid_t caller_uid; +@@ -699,6 +700,7 @@ static void save_caller_context (char ** + * most error messages. + */ + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + caller_uid = getuid (); + caller_is_root = (caller_uid == 0); +diff -up shadow-4.6/src/sulogin.c.libsubid_not_print_error_messages shadow-4.6/src/sulogin.c +--- shadow-4.6/src/sulogin.c.libsubid_not_print_error_messages 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/src/sulogin.c 2021-11-03 09:24:05.710173006 +0100 +@@ -50,6 +50,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + + static char name[BUFSIZ]; + static char pass[BUFSIZ]; +@@ -106,6 +107,7 @@ static RETSIGTYPE catch_signals (unused + #endif + + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + (void) setlocale (LC_ALL, ""); + (void) bindtextdomain (PACKAGE, LOCALEDIR); + (void) textdomain (PACKAGE); +diff -up shadow-4.6/src/useradd.c.libsubid_not_print_error_messages shadow-4.6/src/useradd.c +--- shadow-4.6/src/useradd.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.672172703 +0100 ++++ shadow-4.6/src/useradd.c 2021-11-03 09:24:05.711173014 +0100 +@@ -92,6 +92,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + + /* + * These defaults are used if there is no defaults file. +@@ -2176,6 +2177,7 @@ int main (int argc, char **argv) + * Get my name so that I can use it to report errors. + */ + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + (void) setlocale (LC_ALL, ""); + (void) bindtextdomain (PACKAGE, LOCALEDIR); +diff -up shadow-4.6/src/userdel.c.libsubid_not_print_error_messages shadow-4.6/src/userdel.c +--- shadow-4.6/src/userdel.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.663172632 +0100 ++++ shadow-4.6/src/userdel.c 2021-11-03 09:24:05.712173022 +0100 +@@ -89,6 +89,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + + static char *user_name; + static uid_t user_id; +@@ -939,6 +940,7 @@ int main (int argc, char **argv) + * Get my name so that I can use it to report errors. + */ + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + (void) setlocale (LC_ALL, ""); + (void) bindtextdomain (PACKAGE, LOCALEDIR); + (void) textdomain (PACKAGE); +diff -up shadow-4.6/src/usermod.c.libsubid_not_print_error_messages shadow-4.6/src/usermod.c +--- shadow-4.6/src/usermod.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.674172719 +0100 ++++ shadow-4.6/src/usermod.c 2021-11-03 09:24:05.712173022 +0100 +@@ -102,6 +102,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + + static char *user_name; + static char *user_newname; +@@ -2125,6 +2126,7 @@ int main (int argc, char **argv) + * Get my name so that I can use it to report errors. + */ + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + (void) setlocale (LC_ALL, ""); + (void) bindtextdomain (PACKAGE, LOCALEDIR); +diff -up shadow-4.6/src/vipw.c.libsubid_not_print_error_messages shadow-4.6/src/vipw.c +--- shadow-4.6/src/vipw.c.libsubid_not_print_error_messages 2021-11-03 09:24:05.664172640 +0100 ++++ shadow-4.6/src/vipw.c 2021-11-03 09:24:05.713173030 +0100 +@@ -63,6 +63,7 @@ + * Global variables + */ + const char *Prog; ++FILE *shadow_logfd = NULL; + + static const char *filename, *fileeditname; + static bool filelocked = false; +@@ -438,6 +439,7 @@ int main (int argc, char **argv) + bool do_vipw; + + Prog = Basename (argv[0]); ++ shadow_logfd = stderr; + + (void) setlocale (LC_ALL, ""); + (void) bindtextdomain (PACKAGE, LOCALEDIR); diff --git a/SOURCES/shadow-4.6-libsubid_nsswitch_support.patch b/SOURCES/shadow-4.6-libsubid_nsswitch_support.patch new file mode 100644 index 0000000..4348d0e --- /dev/null +++ b/SOURCES/shadow-4.6-libsubid_nsswitch_support.patch @@ -0,0 +1,1758 @@ +diff -up shadow-4.6/configure.ac.libsubid_nsswitch_support shadow-4.6/configure.ac +--- shadow-4.6/configure.ac.libsubid_nsswitch_support 2021-10-19 13:16:21.989493315 +0200 ++++ shadow-4.6/configure.ac 2021-10-19 13:19:07.743131310 +0200 +@@ -1,6 +1,6 @@ + dnl Process this file with autoconf to produce a configure script. + AC_PREREQ([2.69]) +-m4_define([libsubid_abi_major], 1) ++m4_define([libsubid_abi_major], 2) + m4_define([libsubid_abi_minor], 0) + m4_define([libsubid_abi_micro], 0) + m4_define([libsubid_abi], [libsubid_abi_major.libsubid_abi_minor.libsubid_abi_micro]) +diff -up shadow-4.6/lib/Makefile.am.libsubid_nsswitch_support shadow-4.6/lib/Makefile.am +--- shadow-4.6/lib/Makefile.am.libsubid_nsswitch_support 2021-10-19 13:16:21.973493060 +0200 ++++ shadow-4.6/lib/Makefile.am 2021-10-19 13:16:21.989493315 +0200 +@@ -28,6 +28,7 @@ libshadow_la_SOURCES = \ + groupio.h \ + gshadow.c \ + lockpw.c \ ++ nss.c \ + nscd.c \ + nscd.h \ + sssd.c \ +diff -up shadow-4.6/libmisc/idmapping.h.libsubid_nsswitch_support shadow-4.6/libmisc/idmapping.h +--- shadow-4.6/libmisc/idmapping.h.libsubid_nsswitch_support 2021-10-19 13:16:21.989493315 +0200 ++++ shadow-4.6/libmisc/idmapping.h 2021-10-19 13:19:50.629813857 +0200 +@@ -40,5 +40,7 @@ extern struct map_range *get_map_ranges( + extern void write_mapping(int proc_dir_fd, int ranges, + struct map_range *mappings, const char *map_file); + ++extern void nss_init(char *nsswitch_path); ++ + #endif /* _ID_MAPPING_H_ */ + +diff -up shadow-4.6/libmisc/Makefile.am.libsubid_nsswitch_support shadow-4.6/libmisc/Makefile.am +--- shadow-4.6/libmisc/Makefile.am.libsubid_nsswitch_support 2021-10-19 13:16:21.988493299 +0200 ++++ shadow-4.6/libmisc/Makefile.am 2021-10-19 13:17:03.356151673 +0200 +@@ -3,9 +3,9 @@ EXTRA_DIST = .indent.pro xgetXXbyYY.c + + AM_CPPFLAGS = -I$(top_srcdir)/lib + +-noinst_LIBRARIES = libmisc.a ++noinst_LTLIBRARIES = libmisc.la + +-libmisc_a_SOURCES = \ ++libmisc_la_SOURCES = \ + addgrps.c \ + age.c \ + audit_help.c \ +diff -up shadow-4.6/lib/nss.c.libsubid_nsswitch_support shadow-4.6/lib/nss.c +--- shadow-4.6/lib/nss.c.libsubid_nsswitch_support 2021-10-19 13:16:21.989493315 +0200 ++++ shadow-4.6/lib/nss.c 2021-10-19 13:16:21.989493315 +0200 +@@ -0,0 +1,157 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "prototypes.h" ++#include "../libsubid/subid.h" ++ ++#define NSSWITCH "/etc/nsswitch.conf" ++ ++// NSS plugin handling for subids ++// If nsswitch has a line like ++// subid: sssd ++// then sssd will be consulted for subids. Unlike normal NSS dbs, ++// only one db is supported at a time. That's open to debate, but ++// the subids are a pretty limited resource, and local files seem ++// bound to step on any other allocations leading to insecure ++// conditions. ++static atomic_flag nss_init_started; ++static atomic_bool nss_init_completed; ++ ++static struct subid_nss_ops *subid_nss; ++ ++bool nss_is_initialized() { ++ return atomic_load(&nss_init_completed); ++} ++ ++void nss_exit() { ++ if (nss_is_initialized() && subid_nss) { ++ dlclose(subid_nss->handle); ++ free(subid_nss); ++ subid_nss = NULL; ++ } ++} ++ ++// nsswitch_path is an argument only to support testing. ++void nss_init(char *nsswitch_path) { ++ FILE *nssfp = NULL; ++ char *line = NULL, *p, *token, *saveptr; ++ size_t len = 0; ++ ++ if (atomic_flag_test_and_set(&nss_init_started)) { ++ // Another thread has started nss_init, wait for it to complete ++ while (!atomic_load(&nss_init_completed)) ++ usleep(100); ++ return; ++ } ++ ++ if (!nsswitch_path) ++ nsswitch_path = NSSWITCH; ++ ++ // read nsswitch.conf to check for a line like: ++ // subid: files ++ nssfp = fopen(nsswitch_path, "r"); ++ if (!nssfp) { ++ fprintf(stderr, "Failed opening %s: %m", nsswitch_path); ++ atomic_store(&nss_init_completed, true); ++ return; ++ } ++ while ((getline(&line, &len, nssfp)) != -1) { ++ if (line[0] == '\0' || line[0] == '#') ++ continue; ++ if (strlen(line) < 8) ++ continue; ++ if (strncasecmp(line, "subid:", 6) != 0) ++ continue; ++ p = &line[6]; ++ while ((*p) && isspace(*p)) ++ p++; ++ if (!*p) ++ continue; ++ for (token = strtok_r(p, " \n\t", &saveptr); ++ token; ++ token = strtok_r(NULL, " \n\t", &saveptr)) { ++ char libname[65]; ++ void *h; ++ if (strcmp(token, "files") == 0) { ++ subid_nss = NULL; ++ goto done; ++ } ++ if (strlen(token) > 50) { ++ fprintf(stderr, "Subid NSS module name too long (longer than 50 characters): %s\n", token); ++ fprintf(stderr, "Using files\n"); ++ subid_nss = NULL; ++ goto done; ++ } ++ snprintf(libname, 64, "libsubid_%s.so", token); ++ h = dlopen(libname, RTLD_LAZY); ++ if (!h) { ++ fprintf(stderr, "Error opening %s: %s\n", libname, dlerror()); ++ fprintf(stderr, "Using files\n"); ++ subid_nss = NULL; ++ goto done; ++ } ++ subid_nss = malloc(sizeof(*subid_nss)); ++ if (!subid_nss) { ++ dlclose(h); ++ goto done; ++ } ++ subid_nss->has_range = dlsym(h, "shadow_subid_has_range"); ++ if (!subid_nss->has_range) { ++ fprintf(stderr, "%s did not provide @has_range@\n", libname); ++ dlclose(h); ++ free(subid_nss); ++ subid_nss = NULL; ++ goto done; ++ } ++ subid_nss->list_owner_ranges = dlsym(h, "shadow_subid_list_owner_ranges"); ++ if (!subid_nss->list_owner_ranges) { ++ fprintf(stderr, "%s did not provide @list_owner_ranges@\n", libname); ++ dlclose(h); ++ free(subid_nss); ++ subid_nss = NULL; ++ goto done; ++ } ++ subid_nss->has_any_range = dlsym(h, "shadow_subid_has_any_range"); ++ if (!subid_nss->has_any_range) { ++ fprintf(stderr, "%s did not provide @has_any_range@\n", libname); ++ dlclose(h); ++ free(subid_nss); ++ subid_nss = NULL; ++ goto done; ++ } ++ subid_nss->find_subid_owners = dlsym(h, "shadow_subid_find_subid_owners"); ++ if (!subid_nss->find_subid_owners) { ++ fprintf(stderr, "%s did not provide @find_subid_owners@\n", libname); ++ dlclose(h); ++ free(subid_nss); ++ subid_nss = NULL; ++ goto done; ++ } ++ subid_nss->handle = h; ++ goto done; ++ } ++ fprintf(stderr, "No usable subid NSS module found, using files\n"); ++ // subid_nss has to be null here, but to ease reviews: ++ free(subid_nss); ++ subid_nss = NULL; ++ goto done; ++ } ++ ++done: ++ atomic_store(&nss_init_completed, true); ++ free(line); ++ if (nssfp) { ++ atexit(nss_exit); ++ fclose(nssfp); ++ } ++} ++ ++struct subid_nss_ops *get_subid_nss_handle() { ++ nss_init(NULL); ++ return subid_nss; ++} +diff -up shadow-4.6/lib/prototypes.h.libsubid_nsswitch_support shadow-4.6/lib/prototypes.h +--- shadow-4.6/lib/prototypes.h.libsubid_nsswitch_support 2021-10-19 13:16:21.961492869 +0200 ++++ shadow-4.6/lib/prototypes.h 2021-10-19 13:16:21.989493315 +0200 +@@ -263,6 +263,75 @@ extern void motd (void); + /* myname.c */ + extern /*@null@*//*@only@*/struct passwd *get_my_pwent (void); + ++/* nss.c */ ++#include ++extern void nss_init(char *nsswitch_path); ++extern bool nss_is_initialized(); ++ ++struct subid_nss_ops { ++ /* ++ * nss_has_any_range: does a user own any subid range ++ * ++ * @owner: username ++ * @idtype: subuid or subgid ++ * @result: true if a subid allocation was found for @owner ++ * ++ * returns success if the module was able to determine an answer (true or false), ++ * else an error status. ++ */ ++ enum subid_status (*has_any_range)(const char *owner, enum subid_type idtype, bool *result); ++ ++ /* ++ * nss_has_range: does a user own a given subid range ++ * ++ * @owner: username ++ * @start: first subid in queried range ++ * @count: number of subids in queried range ++ * @idtype: subuid or subgid ++ * @result: true if @owner has been allocated the subid range. ++ * ++ * returns success if the module was able to determine an answer (true or false), ++ * else an error status. ++ */ ++ enum subid_status (*has_range)(const char *owner, unsigned long start, unsigned long count, enum subid_type idtype, bool *result); ++ ++ /* ++ * nss_list_owner_ranges: list the subid ranges delegated to a user. ++ * ++ * @owner - string representing username being queried ++ * @id_type - subuid or subgid ++ * @ranges - pointer to an array of struct subordinate_range pointers, or ++ * NULL. The returned array of struct subordinate_range and its ++ * members must be freed by the caller. ++ * @count - pointer to an integer into which the number of returned ranges ++ * is written. ++ ++ * returns success if the module was able to determine an answer, ++ * else an error status. ++ */ ++ enum subid_status (*list_owner_ranges)(const char *owner, enum subid_type id_type, struct subordinate_range ***ranges, int *count); ++ ++ /* ++ * nss_find_subid_owners: find uids who own a given subuid or subgid. ++ * ++ * @id - the delegated id (subuid or subgid) being queried ++ * @id_type - subuid or subgid ++ * @uids - pointer to an array of uids which will be allocated by ++ * nss_find_subid_owners() ++ * @count - number of uids found ++ * ++ * returns success if the module was able to determine an answer, ++ * else an error status. ++ */ ++ enum subid_status (*find_subid_owners)(unsigned long id, enum subid_type id_type, uid_t **uids, int *count); ++ ++ /* The dlsym handle to close */ ++ void *handle; ++}; ++ ++extern struct subid_nss_ops *get_subid_nss_handle(); ++ ++ + /* pam_pass_non_interactive.c */ + #ifdef USE_PAM + extern int do_pam_passwd_non_interactive (const char *pam_service, +diff -up shadow-4.6/libsubid/api.c.libsubid_nsswitch_support shadow-4.6/libsubid/api.c +--- shadow-4.6/libsubid/api.c.libsubid_nsswitch_support 2021-10-19 13:16:21.986493267 +0200 ++++ shadow-4.6/libsubid/api.c 2021-10-19 13:16:21.991493347 +0200 +@@ -36,134 +36,50 @@ + #include + #include "subordinateio.h" + #include "idmapping.h" +-#include "api.h" ++#include "subid.h" + +-static struct subordinate_range **get_subid_ranges(const char *owner, enum subid_type id_type) ++static ++int get_subid_ranges(const char *owner, enum subid_type id_type, struct subordinate_range ***ranges) + { +- struct subordinate_range **ranges = NULL; +- +- switch (id_type) { +- case ID_TYPE_UID: +- if (!sub_uid_open(O_RDONLY)) { +- return NULL; +- } +- break; +- case ID_TYPE_GID: +- if (!sub_gid_open(O_RDONLY)) { +- return NULL; +- } +- break; +- default: +- return NULL; +- } +- +- ranges = list_owner_ranges(owner, id_type); +- +- if (id_type == ID_TYPE_UID) +- sub_uid_close(); +- else +- sub_gid_close(); +- +- return ranges; ++ return list_owner_ranges(owner, id_type, ranges); + } + +-struct subordinate_range **get_subuid_ranges(const char *owner) ++int get_subuid_ranges(const char *owner, struct subordinate_range ***ranges) + { +- return get_subid_ranges(owner, ID_TYPE_UID); ++ return get_subid_ranges(owner, ID_TYPE_UID, ranges); + } + +-struct subordinate_range **get_subgid_ranges(const char *owner) ++int get_subgid_ranges(const char *owner, struct subordinate_range ***ranges) + { +- return get_subid_ranges(owner, ID_TYPE_GID); ++ return get_subid_ranges(owner, ID_TYPE_GID, ranges); + } + +-void subid_free_ranges(struct subordinate_range **ranges) ++void subid_free_ranges(struct subordinate_range **ranges, int count) + { +- return free_subordinate_ranges(ranges); ++ return free_subordinate_ranges(ranges, count); + } + +-int get_subid_owner(unsigned long id, uid_t **owner, enum subid_type id_type) ++static ++int get_subid_owner(unsigned long id, enum subid_type id_type, uid_t **owner) + { +- int ret = -1; +- +- switch (id_type) { +- case ID_TYPE_UID: +- if (!sub_uid_open(O_RDONLY)) { +- return -1; +- } +- break; +- case ID_TYPE_GID: +- if (!sub_gid_open(O_RDONLY)) { +- return -1; +- } +- break; +- default: +- return -1; +- } +- +- ret = find_subid_owners(id, owner, id_type); +- +- if (id_type == ID_TYPE_UID) +- sub_uid_close(); +- else +- sub_gid_close(); +- +- return ret; ++ return find_subid_owners(id, id_type, owner); + } + + int get_subuid_owners(uid_t uid, uid_t **owner) + { +- return get_subid_owner((unsigned long)uid, owner, ID_TYPE_UID); ++ return get_subid_owner((unsigned long)uid, ID_TYPE_UID, owner); + } + + int get_subgid_owners(gid_t gid, uid_t **owner) + { +- return get_subid_owner((unsigned long)gid, owner, ID_TYPE_GID); ++ return get_subid_owner((unsigned long)gid, ID_TYPE_GID, owner); + } + ++static + bool grant_subid_range(struct subordinate_range *range, bool reuse, + enum subid_type id_type) + { +- bool ret; +- +- switch (id_type) { +- case ID_TYPE_UID: +- if (!sub_uid_lock()) { +- printf("Failed loging subuids (errno %d)\n", errno); +- return false; +- } +- if (!sub_uid_open(O_CREAT | O_RDWR)) { +- printf("Failed opening subuids (errno %d)\n", errno); +- sub_uid_unlock(); +- return false; +- } +- break; +- case ID_TYPE_GID: +- if (!sub_gid_lock()) { +- printf("Failed loging subgids (errno %d)\n", errno); +- return false; +- } +- if (!sub_gid_open(O_CREAT | O_RDWR)) { +- printf("Failed opening subgids (errno %d)\n", errno); +- sub_gid_unlock(); +- return false; +- } +- break; +- default: +- return false; +- } +- +- ret = new_subid_range(range, id_type, reuse); +- +- if (id_type == ID_TYPE_UID) { +- sub_uid_close(); +- sub_uid_unlock(); +- } else { +- sub_gid_close(); +- sub_gid_unlock(); +- } +- +- return ret; ++ return new_subid_range(range, id_type, reuse); + } + + bool grant_subuid_range(struct subordinate_range *range, bool reuse) +@@ -176,56 +92,18 @@ bool grant_subgid_range(struct subordina + return grant_subid_range(range, reuse, ID_TYPE_GID); + } + +-bool free_subid_range(struct subordinate_range *range, enum subid_type id_type) ++static ++bool ungrant_subid_range(struct subordinate_range *range, enum subid_type id_type) + { +- bool ret; +- +- switch (id_type) { +- case ID_TYPE_UID: +- if (!sub_uid_lock()) { +- printf("Failed loging subuids (errno %d)\n", errno); +- return false; +- } +- if (!sub_uid_open(O_CREAT | O_RDWR)) { +- printf("Failed opening subuids (errno %d)\n", errno); +- sub_uid_unlock(); +- return false; +- } +- break; +- case ID_TYPE_GID: +- if (!sub_gid_lock()) { +- printf("Failed loging subgids (errno %d)\n", errno); +- return false; +- } +- if (!sub_gid_open(O_CREAT | O_RDWR)) { +- printf("Failed opening subgids (errno %d)\n", errno); +- sub_gid_unlock(); +- return false; +- } +- break; +- default: +- return false; +- } +- +- ret = release_subid_range(range, id_type); +- +- if (id_type == ID_TYPE_UID) { +- sub_uid_close(); +- sub_uid_unlock(); +- } else { +- sub_gid_close(); +- sub_gid_unlock(); +- } +- +- return ret; ++ return release_subid_range(range, id_type); + } + +-bool free_subuid_range(struct subordinate_range *range) ++bool ungrant_subuid_range(struct subordinate_range *range) + { +- return free_subid_range(range, ID_TYPE_UID); ++ return ungrant_subid_range(range, ID_TYPE_UID); + } + +-bool free_subgid_range(struct subordinate_range *range) ++bool ungrant_subgid_range(struct subordinate_range *range) + { +- return free_subid_range(range, ID_TYPE_GID); ++ return ungrant_subid_range(range, ID_TYPE_GID); + } +diff -up shadow-4.6/libsubid/api.h.libsubid_nsswitch_support shadow-4.6/libsubid/api.h +diff -up shadow-4.6/libsubid/Makefile.am.libsubid_nsswitch_support shadow-4.6/libsubid/Makefile.am +--- shadow-4.6/libsubid/Makefile.am.libsubid_nsswitch_support 2021-10-19 13:16:21.986493267 +0200 ++++ shadow-4.6/libsubid/Makefile.am 2021-10-19 13:16:21.989493315 +0200 +@@ -12,12 +12,14 @@ MISCLIBS = \ + $(LIBSKEY) \ + $(LIBMD) \ + $(LIBCRYPT) \ ++ $(LIBACL) \ ++ $(LIBATTR) \ + $(LIBTCB) + + libsubid_la_LIBADD = \ + $(top_srcdir)/lib/libshadow.la \ +- $(MISCLIBS) \ +- $(top_srcdir)/libmisc/libmisc.a ++ $(top_srcdir)/libmisc/libmisc.la \ ++ $(MISCLIBS) -ldl + + AM_CPPFLAGS = \ + -I${top_srcdir}/lib \ +diff -up shadow-4.6/libsubid/subid.h.libsubid_nsswitch_support shadow-4.6/libsubid/subid.h +--- shadow-4.6/libsubid/subid.h.libsubid_nsswitch_support 2021-10-19 13:16:21.986493267 +0200 ++++ shadow-4.6/libsubid/subid.h 2021-10-19 13:16:21.991493347 +0200 +@@ -1,4 +1,5 @@ + #include ++#include + + #ifndef SUBID_RANGE_DEFINED + #define SUBID_RANGE_DEFINED 1 +@@ -13,5 +14,117 @@ enum subid_type { + ID_TYPE_GID = 2 + }; + ++enum subid_status { ++ SUBID_STATUS_SUCCESS = 0, ++ SUBID_STATUS_UNKNOWN_USER = 1, ++ SUBID_STATUS_ERROR_CONN = 2, ++ SUBID_STATUS_ERROR = 3, ++}; ++ ++/* ++ * get_subuid_ranges: return a list of UID ranges for a user ++ * ++ * @owner: username being queried ++ * @ranges: a pointer to a subordinate range ** in which the result will be ++ * returned. ++ * ++ * returns: number of ranges found, ir < 0 on error. ++ */ ++int get_subuid_ranges(const char *owner, struct subordinate_range ***ranges); ++ ++/* ++ * get_subgid_ranges: return a list of GID ranges for a user ++ * ++ * @owner: username being queried ++ * @ranges: a pointer to a subordinate range ** in which the result will be ++ * returned. ++ * ++ * returns: number of ranges found, ir < 0 on error. ++ */ ++int get_subgid_ranges(const char *owner, struct subordinate_range ***ranges); ++ ++/* ++ * subid_free_ranges: free an array of subordinate_ranges returned by either ++ * get_subuid_ranges() or get_subgid_ranges(). ++ * ++ * @ranges: the ranges to free ++ * @count: the number of ranges in @ranges ++ */ ++void subid_free_ranges(struct subordinate_range **ranges, int count); ++ ++/* ++ * get_subuid_owners: return a list of uids to which the given uid has been ++ * delegated. ++ * ++ * @uid: The subuid being queried ++ * @owners: a pointer to an array of uids into which the results are placed. ++ * The returned array must be freed by the caller. ++ * ++ * Returns the number of uids returned, or < 0 on error. ++ */ ++int get_subuid_owners(uid_t uid, uid_t **owner); ++ ++/* ++ * get_subgid_owners: return a list of uids to which the given gid has been ++ * delegated. ++ * ++ * @uid: The subgid being queried ++ * @owners: a pointer to an array of uids into which the results are placed. ++ * The returned array must be freed by the caller. ++ * ++ * Returns the number of uids returned, or < 0 on error. ++ */ ++int get_subgid_owners(gid_t gid, uid_t **owner); ++ ++/* ++ * grant_subuid_range: assign a subuid range to a user ++ * ++ * @range: pointer to a struct subordinate_range detailing the UID range ++ * to allocate. ->owner must be the username, and ->count must be ++ * filled in. ->start is ignored, and will contain the start ++ * of the newly allocated range, upon success. ++ * ++ * Returns true if the delegation succeeded, false otherwise. If true, ++ * then the range from (range->start, range->start + range->count) will ++ * be delegated to range->owner. ++ */ ++bool grant_subuid_range(struct subordinate_range *range, bool reuse); ++ ++/* ++ * grant_subsid_range: assign a subgid range to a user ++ * ++ * @range: pointer to a struct subordinate_range detailing the GID range ++ * to allocate. ->owner must be the username, and ->count must be ++ * filled in. ->start is ignored, and will contain the start ++ * of the newly allocated range, upon success. ++ * ++ * Returns true if the delegation succeeded, false otherwise. If true, ++ * then the range from (range->start, range->start + range->count) will ++ * be delegated to range->owner. ++ */ ++bool grant_subgid_range(struct subordinate_range *range, bool reuse); ++ ++/* ++ * ungrant_subuid_range: remove a subuid allocation. ++ * ++ * @range: pointer to a struct subordinate_range detailing the UID allocation ++ * to remove. ++ * ++ * Returns true if successful, false if it failed, for instance if the ++ * delegation did not exist. ++ */ ++bool ungrant_subuid_range(struct subordinate_range *range); ++ ++/* ++ * ungrant_subuid_range: remove a subgid allocation. ++ * ++ * @range: pointer to a struct subordinate_range detailing the GID allocation ++ * to remove. ++ * ++ * Returns true if successful, false if it failed, for instance if the ++ * delegation did not exist. ++ */ ++bool ungrant_subgid_range(struct subordinate_range *range); ++ + #define SUBID_NFIELDS 3 + #endif +diff -up shadow-4.6/lib/subordinateio.c.libsubid_nsswitch_support shadow-4.6/lib/subordinateio.c +--- shadow-4.6/lib/subordinateio.c.libsubid_nsswitch_support 2021-10-19 13:16:21.986493267 +0200 ++++ shadow-4.6/lib/subordinateio.c 2021-10-19 13:16:21.989493315 +0200 +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + + /* + * subordinate_dup: create a duplicate range +@@ -316,17 +317,17 @@ static bool append_range(struct subordin + { + struct subordinate_range *tmp; + if (!*ranges) { +- *ranges = malloc(2 * sizeof(struct subordinate_range **)); ++ *ranges = malloc(sizeof(struct subordinate_range *)); + if (!*ranges) + return false; + } else { + struct subordinate_range **new; +- new = realloc(*ranges, (n + 2) * (sizeof(struct subordinate_range **))); ++ new = realloc(*ranges, (n + 1) * (sizeof(struct subordinate_range *))); + if (!new) + return false; + *ranges = new; + } +- (*ranges)[n] = (*ranges)[n+1] = NULL; ++ (*ranges)[n] = NULL; + tmp = subordinate_dup(new); + if (!tmp) + return false; +@@ -334,13 +335,13 @@ static bool append_range(struct subordin + return true; + } + +-void free_subordinate_ranges(struct subordinate_range **ranges) ++void free_subordinate_ranges(struct subordinate_range **ranges, int count) + { + int i; + + if (!ranges) + return; +- for (i = 0; ranges[i]; i++) ++ for (i = 0; i < count; i++) + subordinate_free(ranges[i]); + free(ranges); + } +@@ -607,21 +608,46 @@ int sub_uid_open (int mode) + + bool sub_uid_assigned(const char *owner) + { ++ struct subid_nss_ops *h; ++ bool found; ++ enum subid_status status; ++ h = get_subid_nss_handle(); ++ if (h) { ++ status = h->has_any_range(owner, ID_TYPE_UID, &found); ++ if (status == SUBID_STATUS_SUCCESS && found) ++ return true; ++ return false; ++ } ++ + return range_exists (&subordinate_uid_db, owner); + } + + bool have_sub_uids(const char *owner, uid_t start, unsigned long count) + { ++ struct subid_nss_ops *h; ++ bool found; ++ enum subid_status status; ++ h = get_subid_nss_handle(); ++ if (h) { ++ status = h->has_range(owner, start, count, ID_TYPE_UID, &found); ++ if (status == SUBID_STATUS_SUCCESS && found) ++ return true; ++ return false; ++ } + return have_range (&subordinate_uid_db, owner, start, count); + } + + int sub_uid_add (const char *owner, uid_t start, unsigned long count) + { ++ if (get_subid_nss_handle()) ++ return -EOPNOTSUPP; + return add_range (&subordinate_uid_db, owner, start, count); + } + + int sub_uid_remove (const char *owner, uid_t start, unsigned long count) + { ++ if (get_subid_nss_handle()) ++ return -EOPNOTSUPP; + return remove_range (&subordinate_uid_db, owner, start, count); + } + +@@ -689,21 +715,45 @@ int sub_gid_open (int mode) + + bool have_sub_gids(const char *owner, gid_t start, unsigned long count) + { ++ struct subid_nss_ops *h; ++ bool found; ++ enum subid_status status; ++ h = get_subid_nss_handle(); ++ if (h) { ++ status = h->has_range(owner, start, count, ID_TYPE_GID, &found); ++ if (status == SUBID_STATUS_SUCCESS && found) ++ return true; ++ return false; ++ } + return have_range(&subordinate_gid_db, owner, start, count); + } + + bool sub_gid_assigned(const char *owner) + { ++ struct subid_nss_ops *h; ++ bool found; ++ enum subid_status status; ++ h = get_subid_nss_handle(); ++ if (h) { ++ status = h->has_any_range(owner, ID_TYPE_GID, &found); ++ if (status == SUBID_STATUS_SUCCESS && found) ++ return true; ++ return false; ++ } + return range_exists (&subordinate_gid_db, owner); + } + + int sub_gid_add (const char *owner, gid_t start, unsigned long count) + { ++ if (get_subid_nss_handle()) ++ return -EOPNOTSUPP; + return add_range (&subordinate_gid_db, owner, start, count); + } + + int sub_gid_remove (const char *owner, gid_t start, unsigned long count) + { ++ if (get_subid_nss_handle()) ++ return -EOPNOTSUPP; + return remove_range (&subordinate_gid_db, owner, start, count); + } + +@@ -725,42 +775,78 @@ gid_t sub_gid_find_free_range(gid_t min, + } + + /* +- struct subordinate_range **list_owner_ranges(const char *owner, enum subid_type id_type) ++ * int list_owner_ranges(const char *owner, enum subid_type id_type, struct subordinate_range ***ranges) + * + * @owner: username + * @id_type: UID or GUID ++ * @ranges: pointer to array of ranges into which results will be placed. + * +- * Returns the subuid or subgid ranges which are owned by the specified ++ * Fills in the subuid or subgid ranges which are owned by the specified + * user. Username may be a username or a string representation of a + * UID number. If id_type is UID, then subuids are returned, else +- * subgids are returned. If there is an error, < 0 is returned. ++ * subgids are given. ++ ++ * Returns the number of ranges found, or < 0 on error. + * + * The caller must free the subordinate range list. + */ +-struct subordinate_range **list_owner_ranges(const char *owner, enum subid_type id_type) ++int list_owner_ranges(const char *owner, enum subid_type id_type, struct subordinate_range ***in_ranges) + { + // TODO - need to handle owner being either uid or username +- const struct subordinate_range *range; + struct subordinate_range **ranges = NULL; ++ const struct subordinate_range *range; + struct commonio_db *db; +- int size = 0; ++ enum subid_status status; ++ int count = 0; ++ struct subid_nss_ops *h; ++ ++ *in_ranges = NULL; ++ ++ h = get_subid_nss_handle(); ++ if (h) { ++ status = h->list_owner_ranges(owner, id_type, in_ranges, &count); ++ if (status == SUBID_STATUS_SUCCESS) ++ return count; ++ return -1; ++ } + +- if (id_type == ID_TYPE_UID) ++ switch (id_type) { ++ case ID_TYPE_UID: ++ if (!sub_uid_open(O_RDONLY)) { ++ return -1; ++ } + db = &subordinate_uid_db; +- else ++ break; ++ case ID_TYPE_GID: ++ if (!sub_gid_open(O_RDONLY)) { ++ return -1; ++ } + db = &subordinate_gid_db; ++ break; ++ default: ++ return -1; ++ } + + commonio_rewind(db); + while ((range = commonio_next(db)) != NULL) { + if (0 == strcmp(range->owner, owner)) { +- if (!append_range(&ranges, range, size++)) { +- free_subordinate_ranges(ranges); +- return NULL; ++ if (!append_range(&ranges, range, count++)) { ++ free_subordinate_ranges(ranges, count-1); ++ ranges = NULL; ++ count = -1; ++ goto out; + } + } + } + +- return ranges; ++out: ++ if (id_type == ID_TYPE_UID) ++ sub_uid_close(); ++ else ++ sub_gid_close(); ++ ++ *in_ranges = ranges; ++ return count; + } + + static bool all_digits(const char *str) +@@ -813,17 +899,41 @@ static int append_uids(uid_t **uids, con + return n+1; + } + +-int find_subid_owners(unsigned long id, uid_t **uids, enum subid_type id_type) ++int find_subid_owners(unsigned long id, enum subid_type id_type, uid_t **uids) + { + const struct subordinate_range *range; ++ struct subid_nss_ops *h; ++ enum subid_status status; + struct commonio_db *db; + int n = 0; + +- *uids = NULL; +- if (id_type == ID_TYPE_UID) ++ h = get_subid_nss_handle(); ++ if (h) { ++ status = h->find_subid_owners(id, id_type, uids, &n); ++ // Several ways we could handle the error cases here. ++ if (status != SUBID_STATUS_SUCCESS) ++ return -1; ++ return n; ++ } ++ ++ switch (id_type) { ++ case ID_TYPE_UID: ++ if (!sub_uid_open(O_RDONLY)) { ++ return -1; ++ } + db = &subordinate_uid_db; +- else ++ break; ++ case ID_TYPE_GID: ++ if (!sub_gid_open(O_RDONLY)) { ++ return -1; ++ } + db = &subordinate_gid_db; ++ break; ++ default: ++ return -1; ++ } ++ ++ *uids = NULL; + + commonio_rewind(db); + while ((range = commonio_next(db)) != NULL) { +@@ -834,6 +944,11 @@ int find_subid_owners(unsigned long id, + } + } + ++ if (id_type == ID_TYPE_UID) ++ sub_uid_close(); ++ else ++ sub_gid_close(); ++ + return n; + } + +@@ -841,11 +956,40 @@ bool new_subid_range(struct subordinate_ + { + struct commonio_db *db; + const struct subordinate_range *r; ++ bool ret; + +- if (id_type == ID_TYPE_UID) ++ if (get_subid_nss_handle()) ++ return false; ++ ++ switch (id_type) { ++ case ID_TYPE_UID: ++ if (!sub_uid_lock()) { ++ printf("Failed loging subuids (errno %d)\n", errno); ++ return false; ++ } ++ if (!sub_uid_open(O_CREAT | O_RDWR)) { ++ printf("Failed opening subuids (errno %d)\n", errno); ++ sub_uid_unlock(); ++ return false; ++ } + db = &subordinate_uid_db; +- else ++ break; ++ case ID_TYPE_GID: ++ if (!sub_gid_lock()) { ++ printf("Failed loging subgids (errno %d)\n", errno); ++ return false; ++ } ++ if (!sub_gid_open(O_CREAT | O_RDWR)) { ++ printf("Failed opening subgids (errno %d)\n", errno); ++ sub_gid_unlock(); ++ return false; ++ } + db = &subordinate_gid_db; ++ break; ++ default: ++ return false; ++ } ++ + commonio_rewind(db); + if (reuse) { + while ((r = commonio_next(db)) != NULL) { +@@ -861,20 +1005,74 @@ bool new_subid_range(struct subordinate_ + } + + range->start = find_free_range(db, range->start, ULONG_MAX, range->count); +- if (range->start == ULONG_MAX) +- return false; + +- return add_range(db, range->owner, range->start, range->count) == 1; ++ if (range->start == ULONG_MAX) { ++ ret = false; ++ goto out; ++ } ++ ++ ret = add_range(db, range->owner, range->start, range->count) == 1; ++ ++out: ++ if (id_type == ID_TYPE_UID) { ++ sub_uid_close(); ++ sub_uid_unlock(); ++ } else { ++ sub_gid_close(); ++ sub_gid_unlock(); ++ } ++ ++ return ret; + } + + bool release_subid_range(struct subordinate_range *range, enum subid_type id_type) + { + struct commonio_db *db; +- if (id_type == ID_TYPE_UID) ++ bool ret; ++ ++ if (get_subid_nss_handle()) ++ return false; ++ ++ switch (id_type) { ++ case ID_TYPE_UID: ++ if (!sub_uid_lock()) { ++ printf("Failed loging subuids (errno %d)\n", errno); ++ return false; ++ } ++ if (!sub_uid_open(O_CREAT | O_RDWR)) { ++ printf("Failed opening subuids (errno %d)\n", errno); ++ sub_uid_unlock(); ++ return false; ++ } + db = &subordinate_uid_db; +- else ++ break; ++ case ID_TYPE_GID: ++ if (!sub_gid_lock()) { ++ printf("Failed loging subgids (errno %d)\n", errno); ++ return false; ++ } ++ if (!sub_gid_open(O_CREAT | O_RDWR)) { ++ printf("Failed opening subgids (errno %d)\n", errno); ++ sub_gid_unlock(); ++ return false; ++ } + db = &subordinate_gid_db; +- return remove_range(db, range->owner, range->start, range->count) == 1; ++ break; ++ default: ++ return false; ++ } ++ ++ ret = remove_range(db, range->owner, range->start, range->count) == 1; ++ ++ if (id_type == ID_TYPE_UID) { ++ sub_uid_close(); ++ sub_uid_unlock(); ++ } else { ++ sub_gid_close(); ++ sub_gid_unlock(); ++ } ++ ++ return ret; + } + + #else /* !ENABLE_SUBIDS */ +diff -up shadow-4.6/lib/subordinateio.h.libsubid_nsswitch_support shadow-4.6/lib/subordinateio.h +--- shadow-4.6/lib/subordinateio.h.libsubid_nsswitch_support 2021-10-19 13:16:21.986493267 +0200 ++++ shadow-4.6/lib/subordinateio.h 2021-10-19 13:16:21.989493315 +0200 +@@ -25,11 +25,11 @@ extern int sub_uid_unlock (void); + extern int sub_uid_add (const char *owner, uid_t start, unsigned long count); + extern int sub_uid_remove (const char *owner, uid_t start, unsigned long count); + extern uid_t sub_uid_find_free_range(uid_t min, uid_t max, unsigned long count); +-extern struct subordinate_range **list_owner_ranges(const char *owner, enum subid_type id_type); ++extern int list_owner_ranges(const char *owner, enum subid_type id_type, struct subordinate_range ***ranges); + extern bool new_subid_range(struct subordinate_range *range, enum subid_type id_type, bool reuse); + extern bool release_subid_range(struct subordinate_range *range, enum subid_type id_type); +-extern int find_subid_owners(unsigned long id, uid_t **uids, enum subid_type id_type); +-extern void free_subordinate_ranges(struct subordinate_range **ranges); ++extern int find_subid_owners(unsigned long id, enum subid_type id_type, uid_t **uids); ++extern void free_subordinate_ranges(struct subordinate_range **ranges, int count); + + extern int sub_gid_close(void); + extern bool have_sub_gids(const char *owner, gid_t start, unsigned long count); +diff -up shadow-4.6/src/check_subid_range.c.libsubid_nsswitch_support shadow-4.6/src/check_subid_range.c +--- shadow-4.6/src/check_subid_range.c.libsubid_nsswitch_support 2021-10-19 13:16:21.990493331 +0200 ++++ shadow-4.6/src/check_subid_range.c 2021-10-19 13:16:21.990493331 +0200 +@@ -0,0 +1,48 @@ ++// This program is for testing purposes only. ++// usage is "[program] owner [u|g] start count ++// Exits 0 if owner has subid range starting start, of size count ++// Exits 1 otherwise. ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "defines.h" ++#include "prototypes.h" ++#include "subordinateio.h" ++#include "idmapping.h" ++ ++const char *Prog; ++ ++int main(int argc, char **argv) ++{ ++ char *owner; ++ unsigned long start, count; ++ bool check_uids; ++ Prog = Basename (argv[0]); ++ ++ if (argc != 5) ++ exit(1); ++ ++ owner = argv[1]; ++ check_uids = argv[2][0] == 'u'; ++ start = strtoul(argv[3], NULL, 10); ++ if (start == ULONG_MAX && errno == ERANGE) ++ exit(1); ++ count = strtoul(argv[4], NULL, 10); ++ if (count == ULONG_MAX && errno == ERANGE) ++ exit(1); ++ if (check_uids) { ++ if (have_sub_uids(owner, start, count)) ++ exit(0); ++ exit(1); ++ } ++ if (have_sub_gids(owner, start, count)) ++ exit(0); ++ exit(1); ++} +diff -up shadow-4.6/src/free_subid_range.c.libsubid_nsswitch_support shadow-4.6/src/free_subid_range.c +--- shadow-4.6/src/free_subid_range.c.libsubid_nsswitch_support 2021-10-19 13:16:21.986493267 +0200 ++++ shadow-4.6/src/free_subid_range.c 2021-10-19 13:16:21.991493347 +0200 +@@ -1,6 +1,6 @@ + #include + #include +-#include "api.h" ++#include "subid.h" + #include "stdlib.h" + #include "prototypes.h" + +@@ -37,9 +37,9 @@ int main(int argc, char *argv[]) + range.start = atoi(argv[1]); + range.count = atoi(argv[2]); + if (group) +- ok = free_subgid_range(&range); ++ ok = ungrant_subgid_range(&range); + else +- ok = free_subuid_range(&range); ++ ok = ungrant_subuid_range(&range); + + if (!ok) { + fprintf(stderr, "Failed freeing id range\n"); +diff -up shadow-4.6/src/get_subid_owners.c.libsubid_nsswitch_support shadow-4.6/src/get_subid_owners.c +--- shadow-4.6/src/get_subid_owners.c.libsubid_nsswitch_support 2021-10-19 13:16:21.986493267 +0200 ++++ shadow-4.6/src/get_subid_owners.c 2021-10-19 13:16:21.991493347 +0200 +@@ -1,5 +1,5 @@ + #include +-#include "api.h" ++#include "subid.h" + #include "stdlib.h" + #include "prototypes.h" + +diff -up shadow-4.6/src/list_subid_ranges.c.libsubid_nsswitch_support shadow-4.6/src/list_subid_ranges.c +--- shadow-4.6/src/list_subid_ranges.c.libsubid_nsswitch_support 2021-10-19 13:16:21.987493283 +0200 ++++ shadow-4.6/src/list_subid_ranges.c 2021-10-19 13:16:21.991493347 +0200 +@@ -1,5 +1,5 @@ + #include +-#include "api.h" ++#include "subid.h" + #include "stdlib.h" + #include "prototypes.h" + +@@ -15,7 +15,7 @@ void usage(void) + + int main(int argc, char *argv[]) + { +- int i; ++ int i, count=0; + struct subordinate_range **ranges; + + Prog = Basename (argv[0]); +@@ -23,19 +23,19 @@ int main(int argc, char *argv[]) + usage(); + } + if (argc == 3 && strcmp(argv[1], "-g") == 0) +- ranges = get_subgid_ranges(argv[2]); ++ count = get_subgid_ranges(argv[2], &ranges); + else if (argc == 2 && strcmp(argv[1], "-h") == 0) + usage(); + else +- ranges = get_subuid_ranges(argv[1]); ++ count = get_subuid_ranges(argv[1], &ranges); + if (!ranges) { + fprintf(stderr, "Error fetching ranges\n"); + exit(1); + } +- for (i = 0; ranges[i]; i++) { ++ for (i = 0; i < count; i++) { + printf("%d: %s %lu %lu\n", i, ranges[i]->owner, + ranges[i]->start, ranges[i]->count); + } +- subid_free_ranges(ranges); ++ subid_free_ranges(ranges, count); + return 0; + } +diff -up shadow-4.6/src/Makefile.am.libsubid_nsswitch_support shadow-4.6/src/Makefile.am +--- shadow-4.6/src/Makefile.am.libsubid_nsswitch_support 2021-10-19 13:16:21.988493299 +0200 ++++ shadow-4.6/src/Makefile.am 2021-10-19 13:20:47.920725652 +0200 +@@ -69,7 +69,7 @@ shadowsgidubins = passwd + endif + + LDADD = $(INTLLIBS) \ +- $(top_builddir)/libmisc/libmisc.a \ ++ $(top_builddir)/libmisc/libmisc.la \ + $(top_builddir)/lib/libshadow.la \ + $(LIBTCB) + +@@ -86,17 +86,17 @@ LIBCRYPT_NOPAM = $(LIBCRYPT) + endif + + chage_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) +-newuidmap_LDADD = $(LDADD) $(LIBSELINUX) +-newgidmap_LDADD = $(LDADD) $(LIBSELINUX) ++newuidmap_LDADD = $(LDADD) $(LIBSELINUX) -ldl ++newgidmap_LDADD = $(LDADD) $(LIBSELINUX) -ldl + chfn_LDADD = $(LDADD) $(LIBPAM) $(LIBSELINUX) $(LIBCRYPT_NOPAM) $(LIBSKEY) $(LIBMD) + chgpasswd_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBSELINUX) $(LIBAUDIT) $(LIBCRYPT) + chsh_LDADD = $(LDADD) $(LIBPAM) $(LIBSELINUX) $(LIBCRYPT_NOPAM) $(LIBSKEY) $(LIBMD) + chpasswd_LDADD = $(LDADD) $(LIBPAM) $(LIBSELINUX) $(LIBAUDIT) $(LIBCRYPT) + gpasswd_LDADD = $(LDADD) $(LIBAUDIT) $(LIBSELINUX) $(LIBCRYPT) +-groupadd_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) +-groupdel_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) ++groupadd_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) -ldl ++groupdel_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) -ldl + groupmems_LDADD = $(LDADD) $(LIBPAM) $(LIBSELINUX) +-groupmod_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) ++groupmod_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) -ldl + grpck_LDADD = $(LDADD) $(LIBSELINUX) + grpconv_LDADD = $(LDADD) $(LIBSELINUX) + grpunconv_LDADD = $(LDADD) $(LIBSELINUX) +@@ -106,7 +106,7 @@ login_SOURCES = \ + login_nopam.c + login_LDADD = $(LDADD) $(LIBPAM) $(LIBAUDIT) $(LIBCRYPT_NOPAM) $(LIBSKEY) $(LIBMD) + newgrp_LDADD = $(LDADD) $(LIBAUDIT) $(LIBCRYPT) +-newusers_LDADD = $(LDADD) $(LIBPAM) $(LIBSELINUX) $(LIBCRYPT) ++newusers_LDADD = $(LDADD) $(LIBPAM) $(LIBSELINUX) $(LIBCRYPT) -ldl + nologin_LDADD = + passwd_LDADD = $(LDADD) $(LIBPAM) $(LIBCRACK) $(LIBAUDIT) $(LIBSELINUX) $(LIBCRYPT_NOPAM) + pwck_LDADD = $(LDADD) $(LIBSELINUX) +@@ -117,9 +117,9 @@ su_SOURCES = \ + suauth.c + su_LDADD = $(LDADD) $(LIBPAM) $(LIBAUDIT) $(LIBCRYPT_NOPAM) $(LIBSKEY) $(LIBMD) + sulogin_LDADD = $(LDADD) $(LIBCRYPT) +-useradd_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) $(LIBSEMANAGE) $(LIBACL) $(LIBATTR) +-userdel_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) $(LIBSEMANAGE) +-usermod_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) $(LIBSEMANAGE) $(LIBACL) $(LIBATTR) ++useradd_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) $(LIBSEMANAGE) $(LIBACL) $(LIBATTR) -ldl ++userdel_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) $(LIBSEMANAGE) -ldl ++usermod_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) $(LIBSEMANAGE) $(LIBACL) $(LIBATTR) -ldl + vipw_LDADD = $(LDADD) $(LIBSELINUX) + + install-am: all-am +@@ -143,7 +143,8 @@ if ENABLE_SUBIDS + noinst_PROGRAMS += list_subid_ranges \ + get_subid_owners \ + new_subid_range \ +- free_subid_range ++ free_subid_range \ ++ check_subid_range + + MISCLIBS = \ + $(LIBAUDIT) \ +@@ -158,9 +159,9 @@ MISCLIBS = \ + + list_subid_ranges_LDADD = \ + $(top_builddir)/lib/libshadow.la \ +- $(top_builddir)/libmisc/libmisc.a \ ++ $(top_builddir)/libmisc/libmisc.la \ + $(top_builddir)/libsubid/libsubid.la \ +- $(MISCLIBS) ++ $(MISCLIBS) -ldl + + list_subid_ranges_CPPFLAGS = \ + -I$(top_srcdir)/lib \ +@@ -169,9 +170,9 @@ list_subid_ranges_CPPFLAGS = \ + + get_subid_owners_LDADD = \ + $(top_builddir)/lib/libshadow.la \ +- $(top_builddir)/libmisc/libmisc.a \ ++ $(top_builddir)/libmisc/libmisc.la \ + $(top_builddir)/libsubid/libsubid.la \ +- $(MISCLIBS) ++ $(MISCLIBS) -ldl + + get_subid_owners_CPPFLAGS = \ + -I$(top_srcdir)/lib \ +@@ -185,9 +186,9 @@ new_subid_range_CPPFLAGS = \ + + new_subid_range_LDADD = \ + $(top_builddir)/lib/libshadow.la \ +- $(top_builddir)/libmisc/libmisc.a \ ++ $(top_builddir)/libmisc/libmisc.la \ + $(top_builddir)/libsubid/libsubid.la \ +- $(MISCLIBS) ++ $(MISCLIBS) -ldl + + free_subid_range_CPPFLAGS = \ + -I$(top_srcdir)/lib \ +@@ -196,7 +197,16 @@ free_subid_range_CPPFLAGS = \ + + free_subid_range_LDADD = \ + $(top_builddir)/lib/libshadow.la \ +- $(top_builddir)/libmisc/libmisc.a \ ++ $(top_builddir)/libmisc/libmisc.la \ + $(top_builddir)/libsubid/libsubid.la \ +- $(MISCLIBS) ++ $(MISCLIBS) -ldl ++ ++check_subid_range_CPPFLAGS = \ ++ -I$(top_srcdir)/lib \ ++ -I$(top_srcdir)/libmisc ++ ++check_subid_range_LDADD = \ ++ $(top_builddir)/lib/libshadow.la \ ++ $(top_builddir)/libmisc/libmisc.la \ ++ $(MISCLIBS) -ldl + endif +diff -up shadow-4.6/src/new_subid_range.c.libsubid_nsswitch_support shadow-4.6/src/new_subid_range.c +--- shadow-4.6/src/new_subid_range.c.libsubid_nsswitch_support 2021-10-19 13:16:21.987493283 +0200 ++++ shadow-4.6/src/new_subid_range.c 2021-10-19 13:16:21.991493347 +0200 +@@ -1,6 +1,6 @@ + #include + #include +-#include "api.h" ++#include "subid.h" + #include "stdlib.h" + #include "prototypes.h" + +diff -up shadow-4.6/tests/libsubid/04_nss/empty.libsubid_nsswitch_support shadow-4.6/tests/libsubid/04_nss/empty +diff -up shadow-4.6/tests/libsubid/04_nss/libsubid_zzz.c.libsubid_nsswitch_support shadow-4.6/tests/libsubid/04_nss/libsubid_zzz.c +--- shadow-4.6/tests/libsubid/04_nss/libsubid_zzz.c.libsubid_nsswitch_support 2021-10-19 13:16:21.990493331 +0200 ++++ shadow-4.6/tests/libsubid/04_nss/libsubid_zzz.c 2021-10-19 13:16:21.990493331 +0200 +@@ -0,0 +1,146 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++enum subid_status shadow_subid_has_any_range(const char *owner, enum subid_type t, bool *result) ++{ ++ if (strcmp(owner, "ubuntu") == 0) { ++ *result = true; ++ return SUBID_STATUS_SUCCESS; ++ } ++ if (strcmp(owner, "error") == 0) { ++ *result = false; ++ return SUBID_STATUS_ERROR; ++ } ++ if (strcmp(owner, "unknown") == 0) { ++ *result = false; ++ return SUBID_STATUS_UNKNOWN_USER; ++ } ++ if (strcmp(owner, "conn") == 0) { ++ *result = false; ++ return SUBID_STATUS_ERROR_CONN; ++ } ++ if (t == ID_TYPE_UID) { ++ *result = strcmp(owner, "user1") == 0; ++ return SUBID_STATUS_SUCCESS; ++ } ++ ++ *result = strcmp(owner, "group1") == 0; ++ return SUBID_STATUS_SUCCESS; ++} ++ ++enum subid_status shadow_subid_has_range(const char *owner, unsigned long start, unsigned long count, enum subid_type t, bool *result) ++{ ++ if (strcmp(owner, "ubuntu") == 0 && ++ start >= 200000 && ++ count <= 100000) { ++ *result = true; ++ return SUBID_STATUS_SUCCESS; ++ } ++ *result = false; ++ if (strcmp(owner, "error") == 0) ++ return SUBID_STATUS_ERROR; ++ if (strcmp(owner, "unknown") == 0) ++ return SUBID_STATUS_UNKNOWN_USER; ++ if (strcmp(owner, "conn") == 0) ++ return SUBID_STATUS_ERROR_CONN; ++ ++ if (t == ID_TYPE_UID && strcmp(owner, "user1") != 0) ++ return SUBID_STATUS_SUCCESS; ++ if (t == ID_TYPE_GID && strcmp(owner, "group1") != 0) ++ return SUBID_STATUS_SUCCESS; ++ ++ if (start < 100000) ++ return SUBID_STATUS_SUCCESS; ++ if (count >= 65536) ++ return SUBID_STATUS_SUCCESS; ++ *result = true; ++ return SUBID_STATUS_SUCCESS; ++} ++ ++// So if 'user1' or 'ubuntu' is defined in passwd, we'll return those values, ++// to ease manual testing. For automated testing, if you return those values, ++// we'll return 1000 for ubuntu and 1001 otherwise. ++static uid_t getnamuid(const char *name) { ++ struct passwd *pw; ++ ++ pw = getpwnam(name); ++ if (pw) ++ return pw->pw_uid; ++ ++ // For testing purposes ++ return strcmp(name, "ubuntu") == 0 ? (uid_t)1000 : (uid_t)1001; ++} ++ ++static int alloc_uid(uid_t **uids, uid_t id) { ++ *uids = malloc(sizeof(uid_t)); ++ if (!*uids) ++ return -1; ++ *uids[0] = id; ++ return 1; ++} ++ ++enum subid_status shadow_subid_find_subid_owners(unsigned long id, enum subid_type id_type, uid_t **uids, int *count) ++{ ++ if (id >= 100000 && id < 165536) { ++ *count = alloc_uid(uids, getnamuid("user1")); ++ if (*count == 1) ++ return SUBID_STATUS_SUCCESS; ++ return SUBID_STATUS_ERROR; // out of memory ++ } ++ if (id >= 200000 && id < 300000) { ++ *count = alloc_uid(uids, getnamuid("ubuntu")); ++ if (*count == 1) ++ return SUBID_STATUS_SUCCESS; ++ return SUBID_STATUS_ERROR; // out of memory ++ } ++ *count = 0; // nothing found ++ return SUBID_STATUS_SUCCESS; ++} ++ ++enum subid_status shadow_subid_list_owner_ranges(const char *owner, enum subid_type id_type, struct subordinate_range ***in_ranges, int *count) ++{ ++ struct subordinate_range **ranges; ++ ++ *count = 0; ++ if (strcmp(owner, "error") == 0) ++ return SUBID_STATUS_ERROR; ++ if (strcmp(owner, "unknown") == 0) ++ return SUBID_STATUS_UNKNOWN_USER; ++ if (strcmp(owner, "conn") == 0) ++ return SUBID_STATUS_ERROR_CONN; ++ ++ *ranges = NULL; ++ if (strcmp(owner, "user1") != 0 && strcmp(owner, "ubuntu") != 0 && ++ strcmp(owner, "group1") != 0) ++ return SUBID_STATUS_SUCCESS; ++ if (id_type == ID_TYPE_GID && strcmp(owner, "user1") == 0) ++ return SUBID_STATUS_SUCCESS; ++ if (id_type == ID_TYPE_UID && strcmp(owner, "group1") == 0) ++ return SUBID_STATUS_SUCCESS; ++ ranges = (struct subordinate_range **)malloc(sizeof(struct subordinate_range *)); ++ if (!*ranges) ++ return SUBID_STATUS_ERROR; ++ ranges[0] = (struct subordinate_range *)malloc(sizeof(struct subordinate_range)); ++ if (!ranges[0]) { ++ free(*ranges); ++ *ranges = NULL; ++ return SUBID_STATUS_ERROR; ++ } ++ ranges[0]->owner = strdup(owner); ++ if (strcmp(owner, "user1") == 0 || strcmp(owner, "group1") == 0) { ++ ranges[0]->start = 100000; ++ ranges[0]->count = 65536; ++ } else { ++ ranges[0]->start = 200000; ++ ranges[0]->count = 100000; ++ } ++ ++ *count = 1; ++ *in_ranges = ranges; ++ ++ return SUBID_STATUS_SUCCESS; ++} +diff -up shadow-4.6/tests/libsubid/04_nss/Makefile.libsubid_nsswitch_support shadow-4.6/tests/libsubid/04_nss/Makefile +--- shadow-4.6/tests/libsubid/04_nss/Makefile.libsubid_nsswitch_support 2021-10-19 13:16:21.990493331 +0200 ++++ shadow-4.6/tests/libsubid/04_nss/Makefile 2021-10-19 13:16:21.990493331 +0200 +@@ -0,0 +1,12 @@ ++all: test_nss libsubid_zzz.so ++ ++test_nss: test_nss.c ../../../lib/nss.c ++ gcc -c -I../../../lib/ -I../../.. -o test_nss.o test_nss.c ++ gcc -o test_nss test_nss.o ../../../libmisc/.libs/libmisc.a ../../../lib/.libs/libshadow.a -ldl ++ ++libsubid_zzz.so: libsubid_zzz.c ++ gcc -c -I../../../lib/ -I../../.. -I../../../libmisc -I../../../libsubid libsubid_zzz.c ++ gcc -L../../../libsubid -shared -o libsubid_zzz.so libsubid_zzz.o ../../../lib/.libs/libshadow.a -ldl ++ ++clean: ++ rm -f *.o *.so test_nss +diff -up shadow-4.6/tests/libsubid/04_nss/nsswitch1.conf.libsubid_nsswitch_support shadow-4.6/tests/libsubid/04_nss/nsswitch1.conf +--- shadow-4.6/tests/libsubid/04_nss/nsswitch1.conf.libsubid_nsswitch_support 2021-10-19 13:16:21.990493331 +0200 ++++ shadow-4.6/tests/libsubid/04_nss/nsswitch1.conf 2021-10-19 13:16:21.990493331 +0200 +@@ -0,0 +1,20 @@ ++# /etc/nsswitch.conf ++# ++# Example configuration of GNU Name Service Switch functionality. ++# If you have the `glibc-doc-reference' and `info' packages installed, try: ++# `info libc "Name Service Switch"' for information about this file. ++ ++passwd: files systemd ++group: files systemd ++shadow: files ++gshadow: files ++ ++hosts: files mdns4_minimal [NOTFOUND=return] dns ++networks: files ++ ++protocols: db files ++services: db files ++ethers: db files ++rpc: db files ++ ++netgroup: nis +diff -up shadow-4.6/tests/libsubid/04_nss/nsswitch2.conf.libsubid_nsswitch_support shadow-4.6/tests/libsubid/04_nss/nsswitch2.conf +--- shadow-4.6/tests/libsubid/04_nss/nsswitch2.conf.libsubid_nsswitch_support 2021-10-19 13:16:21.990493331 +0200 ++++ shadow-4.6/tests/libsubid/04_nss/nsswitch2.conf 2021-10-19 13:16:21.990493331 +0200 +@@ -0,0 +1,22 @@ ++# /etc/nsswitch.conf ++# ++# Example configuration of GNU Name Service Switch functionality. ++# If you have the `glibc-doc-reference' and `info' packages installed, try: ++# `info libc "Name Service Switch"' for information about this file. ++ ++passwd: files systemd ++group: files systemd ++shadow: files ++gshadow: files ++ ++hosts: files mdns4_minimal [NOTFOUND=return] dns ++networks: files ++ ++protocols: db files ++services: db files ++ethers: db files ++rpc: db files ++ ++netgroup: nis ++ ++subid: files +diff -up shadow-4.6/tests/libsubid/04_nss/nsswitch3.conf.libsubid_nsswitch_support shadow-4.6/tests/libsubid/04_nss/nsswitch3.conf +--- shadow-4.6/tests/libsubid/04_nss/nsswitch3.conf.libsubid_nsswitch_support 2021-10-19 13:16:21.990493331 +0200 ++++ shadow-4.6/tests/libsubid/04_nss/nsswitch3.conf 2021-10-19 13:16:21.990493331 +0200 +@@ -0,0 +1,22 @@ ++# /etc/nsswitch.conf ++# ++# Example configuration of GNU Name Service Switch functionality. ++# If you have the `glibc-doc-reference' and `info' packages installed, try: ++# `info libc "Name Service Switch"' for information about this file. ++ ++passwd: files systemd ++group: files systemd ++shadow: files ++gshadow: files ++ ++hosts: files mdns4_minimal [NOTFOUND=return] dns ++networks: files ++ ++protocols: db files ++services: db files ++ethers: db files ++rpc: db files ++ ++netgroup: nis ++ ++subid: zzz +diff -up shadow-4.6/tests/libsubid/04_nss/subidnss.test.libsubid_nsswitch_support shadow-4.6/tests/libsubid/04_nss/subidnss.test +--- shadow-4.6/tests/libsubid/04_nss/subidnss.test.libsubid_nsswitch_support 2021-10-19 13:16:21.990493331 +0200 ++++ shadow-4.6/tests/libsubid/04_nss/subidnss.test 2021-10-19 13:16:21.990493331 +0200 +@@ -0,0 +1,22 @@ ++#!/bin/sh ++ ++set -e ++ ++cd $(dirname $0) ++ ++. ../../common/config.sh ++. ../../common/log.sh ++ ++make ++ ++export LD_LIBRARY_PATH=.:../../../lib/.libs:$LD_LIBRARY_PATH ++ ++./test_nss 1 ++./test_nss 2 ++./test_nss 3 ++ ++unshare -Urm ./test_range ++ ++log_status "$0" "SUCCESS" ++ ++trap '' 0 +diff -up shadow-4.6/tests/libsubid/04_nss/test_nss.c.libsubid_nsswitch_support shadow-4.6/tests/libsubid/04_nss/test_nss.c +--- shadow-4.6/tests/libsubid/04_nss/test_nss.c.libsubid_nsswitch_support 2021-10-19 13:16:21.990493331 +0200 ++++ shadow-4.6/tests/libsubid/04_nss/test_nss.c 2021-10-19 13:16:21.990493331 +0200 +@@ -0,0 +1,72 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++extern bool nss_is_initialized(); ++extern struct subid_nss_ops *get_subid_nss_handle(); ++ ++void test1() { ++ // nsswitch1 has no subid: entry ++ setenv("LD_LIBRARY_PATH", ".", 1); ++ printf("Test with no subid entry\n"); ++ nss_init("./nsswitch1.conf"); ++ if (!nss_is_initialized() || get_subid_nss_handle()) ++ exit(1); ++ // second run should change nothing ++ printf("Test with no subid entry, second run\n"); ++ nss_init("./nsswitch1.conf"); ++ if (!nss_is_initialized() || get_subid_nss_handle()) ++ exit(1); ++} ++ ++void test2() { ++ // nsswitch2 has a subid: files entry ++ printf("test with 'files' subid entry\n"); ++ nss_init("./nsswitch2.conf"); ++ if (!nss_is_initialized() || get_subid_nss_handle()) ++ exit(1); ++ // second run should change nothing ++ printf("test with 'files' subid entry, second run\n"); ++ nss_init("./nsswitch2.conf"); ++ if (!nss_is_initialized() || get_subid_nss_handle()) ++ exit(1); ++} ++ ++void test3() { ++ // nsswitch3 has a subid: testnss entry ++ printf("test with 'test' subid entry\n"); ++ nss_init("./nsswitch3.conf"); ++ if (!nss_is_initialized() || !get_subid_nss_handle()) ++ exit(1); ++ // second run should change nothing ++ printf("test with 'test' subid entry, second run\n"); ++ nss_init("./nsswitch3.conf"); ++ if (!nss_is_initialized() || !get_subid_nss_handle()) ++ exit(1); ++} ++ ++const char *Prog; ++ ++int main(int argc, char *argv[]) ++{ ++ int which; ++ ++ Prog = Basename(argv[0]); ++ ++ if (argc < 1) ++ exit(1); ++ ++ which = atoi(argv[1]); ++ switch(which) { ++ case 1: test1(); break; ++ case 2: test2(); break; ++ case 3: test3(); break; ++ default: exit(1); ++ } ++ ++ printf("nss parsing tests done\n"); ++ exit(0); ++} +diff -up shadow-4.6/tests/libsubid/04_nss/test_range.libsubid_nsswitch_support shadow-4.6/tests/libsubid/04_nss/test_range +--- shadow-4.6/tests/libsubid/04_nss/test_range.libsubid_nsswitch_support 2021-10-19 13:16:21.991493347 +0200 ++++ shadow-4.6/tests/libsubid/04_nss/test_range 2021-10-19 13:16:21.991493347 +0200 +@@ -0,0 +1,50 @@ ++#!/bin/sh ++ ++set -x ++ ++echo "starting check_range tests" ++ ++export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH ++mount --bind ./nsswitch3.conf /etc/nsswitch.conf ++cleanup1() { ++ umount /etc/nsswitch.conf ++} ++trap cleanup1 EXIT HUP INT TERM ++../../../src/check_subid_range user1 u 100000 65535 ++if [ $? -ne 0 ]; then ++ exit 1 ++fi ++../../../src/check_subid_range user2 u 100000 65535 ++if [ $? -eq 0 ]; then ++ exit 1 ++fi ++../../../src/check_subid_range unknown u 100000 65535 ++if [ $? -eq 0 ]; then ++ exit 1 ++fi ++../../../src/check_subid_range error u 100000 65535 ++if [ $? -eq 0 ]; then ++ exit 1 ++fi ++../../../src/check_subid_range user1 u 1000 65535 ++if [ $? -eq 0 ]; then ++ exit 1 ++fi ++ ++umount /etc/nsswitch.conf ++ ++mount --bind ./nsswitch1.conf /etc/nsswitch.conf ++mount --bind ./empty /etc/subuid ++ ++cleanup2() { ++ umount /etc/subuid ++ umount /etc/nsswitch.conf ++} ++trap cleanup2 EXIT HUP INT TERM ++../../../src/check_subid_range user1 u 100000 65535 ++if [ $? -eq 0 ]; then ++ exit 1 ++fi ++ ++echo "check_range tests complete" ++exit 0 +diff -up shadow-4.6/tests/run_some.libsubid_nsswitch_support shadow-4.6/tests/run_some +--- shadow-4.6/tests/run_some.libsubid_nsswitch_support 2021-10-19 13:16:21.987493283 +0200 ++++ shadow-4.6/tests/run_some 2021-10-19 13:16:21.991493347 +0200 +@@ -123,6 +123,7 @@ run_test ./su/13_su_child_success/su.tes + run_test ./libsubid/01_list_ranges/list_ranges.test + run_test ./libsubid/02_get_subid_owners/get_subid_owners.test + run_test ./libsubid/03_add_remove/add_remove_subids.test ++run_test ./libsubid/04_nss/subidnss.test + + echo + echo "$succeeded test(s) passed" diff --git a/SOURCES/shadow-4.6-libsubid_simplify_ranges_variable.patch b/SOURCES/shadow-4.6-libsubid_simplify_ranges_variable.patch new file mode 100644 index 0000000..4cd848b --- /dev/null +++ b/SOURCES/shadow-4.6-libsubid_simplify_ranges_variable.patch @@ -0,0 +1,264 @@ +diff -up shadow-4.8.1/configure.ac.libsubid_simplify_ranges_variable shadow-4.8.1/configure.ac +--- shadow-4.8.1/configure.ac.libsubid_simplify_ranges_variable 2021-05-24 15:02:56.165917066 +0200 ++++ shadow-4.8.1/configure.ac 2021-05-24 15:02:56.184917324 +0200 +@@ -1,6 +1,6 @@ + dnl Process this file with autoconf to produce a configure script. + AC_PREREQ([2.69]) +-m4_define([libsubid_abi_major], 2) ++m4_define([libsubid_abi_major], 3) + m4_define([libsubid_abi_minor], 0) + m4_define([libsubid_abi_micro], 0) + m4_define([libsubid_abi], [libsubid_abi_major.libsubid_abi_minor.libsubid_abi_micro]) +diff -up shadow-4.8.1/lib/prototypes.h.libsubid_simplify_ranges_variable shadow-4.8.1/lib/prototypes.h +--- shadow-4.8.1/lib/prototypes.h.libsubid_simplify_ranges_variable 2021-05-24 15:02:56.184917324 +0200 ++++ shadow-4.8.1/lib/prototypes.h 2021-05-24 16:38:57.610619467 +0200 +@@ -309,16 +309,15 @@ struct subid_nss_ops { + * + * @owner - string representing username being queried + * @id_type - subuid or subgid +- * @ranges - pointer to an array of struct subordinate_range pointers, or +- * NULL. The returned array of struct subordinate_range and its +- * members must be freed by the caller. ++ * @ranges - pointer to an array of struct subid_range, or NULL. The ++ * returned array must be freed by the caller. + * @count - pointer to an integer into which the number of returned ranges + * is written. + + * returns success if the module was able to determine an answer, + * else an error status. + */ +- enum subid_status (*list_owner_ranges)(const char *owner, enum subid_type id_type, struct subordinate_range ***ranges, int *count); ++ enum subid_status (*list_owner_ranges)(const char *owner, enum subid_type id_type, struct subid_range **ranges, int *count); + + /* + * nss_find_subid_owners: find uids who own a given subuid or subgid. +diff -up shadow-4.8.1/libsubid/api.c.libsubid_simplify_ranges_variable shadow-4.8.1/libsubid/api.c +--- shadow-4.8.1/libsubid/api.c.libsubid_simplify_ranges_variable 2021-05-24 15:03:01.467989079 +0200 ++++ shadow-4.8.1/libsubid/api.c 2021-05-24 16:42:32.091584531 +0200 +@@ -68,26 +68,21 @@ bool libsubid_init(const char *progname, + } + + static +-int get_subid_ranges(const char *owner, enum subid_type id_type, struct subordinate_range ***ranges) ++int get_subid_ranges(const char *owner, enum subid_type id_type, struct subid_range **ranges) + { + return list_owner_ranges(owner, id_type, ranges); + } + +-int get_subuid_ranges(const char *owner, struct subordinate_range ***ranges) ++int get_subuid_ranges(const char *owner, struct subid_range **ranges) + { + return get_subid_ranges(owner, ID_TYPE_UID, ranges); + } + +-int get_subgid_ranges(const char *owner, struct subordinate_range ***ranges) ++int get_subgid_ranges(const char *owner, struct subid_range **ranges) + { + return get_subid_ranges(owner, ID_TYPE_GID, ranges); + } + +-void subid_free_ranges(struct subordinate_range **ranges, int count) +-{ +- return free_subordinate_ranges(ranges, count); +-} +- + static + int get_subid_owner(unsigned long id, enum subid_type id_type, uid_t **owner) + { +diff -up shadow-4.8.1/libsubid/subid.h.libsubid_simplify_ranges_variable shadow-4.8.1/libsubid/subid.h +--- shadow-4.8.1/libsubid/subid.h.libsubid_simplify_ranges_variable 2021-05-24 15:03:01.468989093 +0200 ++++ shadow-4.8.1/libsubid/subid.h 2021-05-24 16:43:49.697657383 +0200 +@@ -3,6 +3,15 @@ + + #ifndef SUBID_RANGE_DEFINED + #define SUBID_RANGE_DEFINED 1 ++ ++/* subid_range is just a starting point and size of a range */ ++struct subid_range { ++ unsigned long start; ++ unsigned long count; ++}; ++ ++/* subordinage_range is a subid_range plus an owner, representing ++ * a range in /etc/subuid or /etc/subgid */ + struct subordinate_range { + const char *owner; + unsigned long start; +@@ -41,32 +50,27 @@ bool libsubid_init(const char *progname, + * get_subuid_ranges: return a list of UID ranges for a user + * + * @owner: username being queried +- * @ranges: a pointer to a subordinate range ** in which the result will be +- * returned. ++ * @ranges: a pointer to an array of subid_range structs in which the result ++ * will be returned. ++ * ++ * The caller must free(ranges) when done. + * + * returns: number of ranges found, ir < 0 on error. + */ +-int get_subuid_ranges(const char *owner, struct subordinate_range ***ranges); ++int get_subuid_ranges(const char *owner, struct subid_range **ranges); + + /* + * get_subgid_ranges: return a list of GID ranges for a user + * + * @owner: username being queried +- * @ranges: a pointer to a subordinate range ** in which the result will be +- * returned. ++ * @ranges: a pointer to an array of subid_range structs in which the result ++ * will be returned. + * +- * returns: number of ranges found, ir < 0 on error. +- */ +-int get_subgid_ranges(const char *owner, struct subordinate_range ***ranges); +- +-/* +- * subid_free_ranges: free an array of subordinate_ranges returned by either +- * get_subuid_ranges() or get_subgid_ranges(). ++ * The caller must free(ranges) when done. + * +- * @ranges: the ranges to free +- * @count: the number of ranges in @ranges ++ * returns: number of ranges found, ir < 0 on error. + */ +-void subid_free_ranges(struct subordinate_range **ranges, int count); ++int get_subgid_ranges(const char *owner, struct subid_range **ranges); + + /* + * get_subuid_owners: return a list of uids to which the given uid has been +diff -up shadow-4.8.1/lib/subordinateio.c.libsubid-simplify shadow-4.8.1/lib/subordinateio.c +--- shadow-4.8.1/lib/subordinateio.c.libsubid-simplify 2021-05-24 17:27:38.721035241 +0200 ++++ shadow-4.8.1/lib/subordinateio.c 2021-05-24 17:28:06.481420946 +0200 +@@ -11,6 +11,7 @@ + #include + #include "commonio.h" + #include "subordinateio.h" ++#include "../libsubid/subid.h" + #include + #include + #include +@@ -308,25 +309,21 @@ static bool have_range(struct commonio_d + return false; + } + +-static bool append_range(struct subordinate_range ***ranges, const struct subordinate_range *new, int n) ++static bool append_range(struct subid_range **ranges, const struct subordinate_range *new, int n) + { +- struct subordinate_range *tmp; + if (!*ranges) { +- *ranges = malloc(sizeof(struct subordinate_range *)); ++ *ranges = malloc(sizeof(struct subid_range)); + if (!*ranges) + return false; + } else { +- struct subordinate_range **new; +- new = realloc(*ranges, (n + 1) * (sizeof(struct subordinate_range *))); +- if (!new) ++ struct subid_range *alloced; ++ alloced = realloc(*ranges, (n + 1) * (sizeof(struct subid_range))); ++ if (!alloced) + return false; +- *ranges = new; ++ *ranges = alloced; + } +- (*ranges)[n] = NULL; +- tmp = subordinate_dup(new); +- if (!tmp) +- return false; +- (*ranges)[n] = tmp; ++ (*ranges)[n].start = new->start; ++ (*ranges)[n].count = new->count; + return true; + } + +@@ -785,10 +782,10 @@ gid_t sub_gid_find_free_range(gid_t min, + * + * The caller must free the subordinate range list. + */ +-int list_owner_ranges(const char *owner, enum subid_type id_type, struct subordinate_range ***in_ranges) ++int list_owner_ranges(const char *owner, enum subid_type id_type, struct subid_range **in_ranges) + { + // TODO - need to handle owner being either uid or username +- struct subordinate_range **ranges = NULL; ++ struct subid_range *ranges = NULL; + const struct subordinate_range *range; + struct commonio_db *db; + enum subid_status status; +@@ -826,7 +823,7 @@ int list_owner_ranges(const char *owner, + while ((range = commonio_next(db)) != NULL) { + if (0 == strcmp(range->owner, owner)) { + if (!append_range(&ranges, range, count++)) { +- free_subordinate_ranges(ranges, count-1); ++ free(ranges); + ranges = NULL; + count = -1; + goto out; +diff -up shadow-4.8.1/lib/subordinateio.h.libsubid_simplify_ranges_variable shadow-4.8.1/lib/subordinateio.h +--- shadow-4.8.1/lib/subordinateio.h.libsubid_simplify_ranges_variable 2021-05-24 15:03:01.467989079 +0200 ++++ shadow-4.8.1/lib/subordinateio.h 2021-05-24 16:40:56.978269647 +0200 +@@ -25,7 +25,7 @@ extern int sub_uid_unlock (void); + extern int sub_uid_add (const char *owner, uid_t start, unsigned long count); + extern int sub_uid_remove (const char *owner, uid_t start, unsigned long count); + extern uid_t sub_uid_find_free_range(uid_t min, uid_t max, unsigned long count); +-extern int list_owner_ranges(const char *owner, enum subid_type id_type, struct subordinate_range ***ranges); ++extern int list_owner_ranges(const char *owner, enum subid_type id_type, struct subid_range **ranges); + extern bool new_subid_range(struct subordinate_range *range, enum subid_type id_type, bool reuse); + extern bool release_subid_range(struct subordinate_range *range, enum subid_type id_type); + extern int find_subid_owners(unsigned long id, enum subid_type id_type, uid_t **uids); +diff -up shadow-4.8.1/src/list_subid_ranges.c.libsubid_simplify_ranges_variable shadow-4.8.1/src/list_subid_ranges.c +--- shadow-4.8.1/src/list_subid_ranges.c.libsubid_simplify_ranges_variable 2021-05-24 15:03:01.468989093 +0200 ++++ shadow-4.8.1/src/list_subid_ranges.c 2021-05-24 16:45:10.884779740 +0200 +@@ -17,27 +17,29 @@ void usage(void) + int main(int argc, char *argv[]) + { + int i, count=0; +- struct subordinate_range **ranges; ++ struct subid_range *ranges; ++ const char *owner; + + Prog = Basename (argv[0]); + shadow_logfd = stderr; +- if (argc < 2) { ++ if (argc < 2) + usage(); +- } +- if (argc == 3 && strcmp(argv[1], "-g") == 0) +- count = get_subgid_ranges(argv[2], &ranges); +- else if (argc == 2 && strcmp(argv[1], "-h") == 0) ++ owner = argv[1]; ++ if (argc == 3 && strcmp(argv[1], "-g") == 0) { ++ owner = argv[2]; ++ count = get_subgid_ranges(owner, &ranges); ++ } else if (argc == 2 && strcmp(argv[1], "-h") == 0) { + usage(); +- else +- count = get_subuid_ranges(argv[1], &ranges); ++ } else { ++ count = get_subuid_ranges(owner, &ranges); ++ } + if (!ranges) { + fprintf(stderr, "Error fetching ranges\n"); + exit(1); + } + for (i = 0; i < count; i++) { +- printf("%d: %s %lu %lu\n", i, ranges[i]->owner, +- ranges[i]->start, ranges[i]->count); ++ printf("%d: %s %lu %lu\n", i, owner, ++ ranges[i].start, ranges[i].count); + } +- subid_free_ranges(ranges, count); + return 0; + } +diff -up shadow-4.8.1/tests/libsubid/04_nss/libsubid_zzz.c.libsubid_simplify_ranges_variable shadow-4.8.1/tests/libsubid/04_nss/libsubid_zzz.c +--- shadow-4.8.1/tests/libsubid/04_nss/libsubid_zzz.c.libsubid_simplify_ranges_variable 2021-05-24 15:02:56.166917079 +0200 ++++ shadow-4.8.1/tests/libsubid/04_nss/libsubid_zzz.c 2021-05-24 15:03:01.469989106 +0200 +@@ -113,7 +113,7 @@ enum subid_status shadow_subid_list_owne + if (strcmp(owner, "conn") == 0) + return SUBID_STATUS_ERROR_CONN; + +- *ranges = NULL; ++ *in_ranges = NULL; + if (strcmp(owner, "user1") != 0 && strcmp(owner, "ubuntu") != 0 && + strcmp(owner, "group1") != 0) + return SUBID_STATUS_SUCCESS; diff --git a/SOURCES/shadow-4.6-man-mention-nss-in-newuidmap.patch b/SOURCES/shadow-4.6-man-mention-nss-in-newuidmap.patch new file mode 100644 index 0000000..e26cfa7 --- /dev/null +++ b/SOURCES/shadow-4.6-man-mention-nss-in-newuidmap.patch @@ -0,0 +1,44 @@ +From 186b1b7ac1a68d0fcc618a22da1a99232b420911 Mon Sep 17 00:00:00 2001 +From: Serge Hallyn +Date: Tue, 4 May 2021 14:39:26 -0500 +Subject: [PATCH] manpages: mention NSS in new[ug]idmap manpages + +Closes #328 + +Signed-off-by: Serge Hallyn +--- + man/newgidmap.1.xml | 3 ++- + man/newuidmap.1.xml | 3 ++- + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/man/newgidmap.1.xml b/man/newgidmap.1.xml +index 71b03e56..76fc1e30 100644 +--- a/man/newgidmap.1.xml ++++ b/man/newgidmap.1.xml +@@ -88,7 +88,8 @@ + DESCRIPTION + + The newgidmap sets /proc/[pid]/gid_map based on its +- command line arguments and the gids allowed in /etc/subgid. ++ command line arguments and the gids allowed (either in /etc/subgid or ++ through the configured NSS subid module). + Note that the root user is not exempted from the requirement for a valid + /etc/subgid entry. + +diff --git a/man/newuidmap.1.xml b/man/newuidmap.1.xml +index a6f1f085..44eca50a 100644 +--- a/man/newuidmap.1.xml ++++ b/man/newuidmap.1.xml +@@ -88,7 +88,8 @@ + DESCRIPTION + + The newuidmap sets /proc/[pid]/uid_map based on its +- command line arguments and the uids allowed in /etc/subuid. ++ command line arguments and the uids allowed (either in /etc/subuid or ++ through the configured NSS subid module). + Note that the root user is not exempted from the requirement for a valid + /etc/subuid entry. + +-- +2.30.2 + diff --git a/SOURCES/shadow-4.6-man_clarify_subid_delegation.patch b/SOURCES/shadow-4.6-man_clarify_subid_delegation.patch new file mode 100644 index 0000000..47d4d46 --- /dev/null +++ b/SOURCES/shadow-4.6-man_clarify_subid_delegation.patch @@ -0,0 +1,166 @@ +diff -up shadow-4.6/man/newgidmap.1.xml.man_clarify_subid_delegation shadow-4.6/man/newgidmap.1.xml +--- shadow-4.6/man/newgidmap.1.xml.man_clarify_subid_delegation 2021-11-03 09:58:34.176484342 +0100 ++++ shadow-4.6/man/newgidmap.1.xml 2021-11-03 09:58:34.191484452 +0100 +@@ -80,10 +80,15 @@ + + DESCRIPTION + +- The newgidmap sets /proc/[pid]/gid_map based on its +- command line arguments and the gids allowed (either in /etc/subgid or +- through the configured NSS subid module). +- Note that the root user is not exempted from the requirement for a valid ++ The newgidmap sets /proc/[pid]/gid_map ++ based on its command line arguments and the gids allowed. Subgid ++ delegation can either be managed via /etc/subgid ++ or through the configured NSS subid module. These options are mutually ++ exclusive. ++ ++ ++ ++ Note that the root group is not exempted from the requirement for a valid + /etc/subgid entry. + + +diff -up shadow-4.6/man/newuidmap.1.xml.man_clarify_subid_delegation shadow-4.6/man/newuidmap.1.xml +--- shadow-4.6/man/newuidmap.1.xml.man_clarify_subid_delegation 2021-11-03 09:58:34.176484342 +0100 ++++ shadow-4.6/man/newuidmap.1.xml 2021-11-03 09:58:34.191484452 +0100 +@@ -80,9 +80,14 @@ + + DESCRIPTION + +- The newuidmap sets /proc/[pid]/uid_map based on its +- command line arguments and the uids allowed (either in /etc/subuid or +- through the configured NSS subid module). ++ The newuidmap sets /proc/[pid]/uid_map ++ based on its command line arguments and the uids allowed. Subuid ++ delegation can either be managed via /etc/subuid or ++ through the configured NSS subid module. These options are mutually ++ exclusive. ++ ++ ++ + Note that the root user is not exempted from the requirement for a valid + /etc/subuid entry. + +diff -up shadow-4.6/man/subgid.5.xml.man_clarify_subid_delegation shadow-4.6/man/subgid.5.xml +--- shadow-4.6/man/subgid.5.xml.man_clarify_subid_delegation 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/man/subgid.5.xml 2021-11-03 09:59:55.752084920 +0100 +@@ -32,6 +32,18 @@ + + ]> + ++ ++ ++ Eric ++ Biederman ++ Creation, 2013 ++ ++ ++ Iker ++ Pedrosa ++ Developer, 2021 ++ ++ + + subgid + 5 +@@ -41,12 +53,37 @@ + + + subgid +- the subordinate gid file ++ the configuration for subordinate group ids + + + + DESCRIPTION + ++ Subgid authorizes a group id to map ranges of group ids from its namespace ++ into child namespaces. ++ ++ ++ The delegation of the subordinate gids can be configured via the ++ subid field in ++ /etc/nsswitch.conf file. Only one value can be set ++ as the delegation source. Setting this field to ++ files configures the delegation of gids to ++ /etc/subgid. Setting any other value treats ++ the delegation as a plugin following with a name of the form ++ libsubid_$value.so. If the value or plugin is ++ missing, then the subordinate gid delegation falls back to ++ files. ++ ++ ++ Note, that groupadd will only create entries in ++ /etc/subgid if subid delegation is managed via subid ++ files. ++ ++ ++ ++ ++ LOCAL SUBORDINATE DELEGATION ++ + Each line in /etc/subgid contains + a user name and a range of subordinate group ids that user + is allowed to use. +diff -up shadow-4.6/man/subuid.5.xml.man_clarify_subid_delegation shadow-4.6/man/subuid.5.xml +--- shadow-4.6/man/subuid.5.xml.man_clarify_subid_delegation 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/man/subuid.5.xml 2021-11-03 10:00:18.888255255 +0100 +@@ -32,6 +32,18 @@ + + ]> + ++ ++ ++ Eric ++ Biederman ++ Creation, 2013 ++ ++ ++ Iker ++ Pedrosa ++ Developer, 2021 ++ ++ + + subuid + 5 +@@ -41,12 +53,37 @@ + + + subuid +- the subordinate uid file ++ the configuration for subordinate user ids + + + + DESCRIPTION + ++ Subuid authorizes a user id to map ranges of user ids from its namespace ++ into child namespaces. ++ ++ ++ The delegation of the subordinate uids can be configured via the ++ subid field in ++ /etc/nsswitch.conf file. Only one value can be set ++ as the delegation source. Setting this field to ++ files configures the delegation of uids to ++ /etc/subuid. Setting any other value treats ++ the delegation as a plugin following with a name of the form ++ libsubid_$value.so. If the value or plugin is ++ missing, then the subordinate uid delegation falls back to ++ files. ++ ++ ++ Note, that useradd will only create entries in ++ /etc/subuid if subid delegation is managed via subid ++ files. ++ ++ ++ ++ ++ LOCAL SUBORDINATE DELEGATION ++ + Each line in /etc/subuid contains + a user name and a range of subordinate user ids that user + is allowed to use. diff --git a/SOURCES/shadow-4.6-manfix.patch b/SOURCES/shadow-4.6-manfix.patch new file mode 100644 index 0000000..80ae198 --- /dev/null +++ b/SOURCES/shadow-4.6-manfix.patch @@ -0,0 +1,349 @@ +diff -up shadow-4.6/man/groupmems.8.xml.manfix shadow-4.6/man/groupmems.8.xml +--- shadow-4.6/man/groupmems.8.xml.manfix 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/man/groupmems.8.xml 2020-10-23 13:15:24.105387634 +0200 +@@ -179,20 +179,10 @@ + + SETUP + +- The groupmems executable should be in mode +- 2770 as user root and in group +- groups. The system administrator can add users to +- group groups to allow or disallow them using the +- groupmems utility to manage their own group +- membership list. ++ In this operating system the groupmems executable ++ is not setuid and regular users cannot use it to manipulate ++ the membership of their own group. + +- +- +- $ groupadd -r groups +- $ chmod 2770 groupmems +- $ chown root.groups groupmems +- $ groupmems -g groups -a gk4 +- + + + +diff -up shadow-4.6/man/chage.1.xml.manfix shadow-4.6/man/chage.1.xml +--- shadow-4.6/man/chage.1.xml.manfix 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/man/chage.1.xml 2020-10-23 13:15:24.105387634 +0200 +@@ -102,6 +102,9 @@ + Set the number of days since January 1st, 1970 when the password + was last changed. The date may also be expressed in the format + YYYY-MM-DD (or the format more commonly used in your area). ++ If the LAST_DAY is set to ++ 0 the user is forced to change his password ++ on the next log on. + + + +@@ -119,6 +122,13 @@ + system again. + + ++ For example the following can be used to set an account to expire ++ in 180 days: ++ ++ ++ chage -E $(date -d +180days +%Y-%m-%d) ++ ++ + Passing the number -1 as the + EXPIRE_DATE will remove an account + expiration date. +@@ -233,6 +243,18 @@ + The chage program requires a shadow password file to + be available. + ++ ++ The chage program will report only the information from the shadow ++ password file. This implies that configuration from other sources ++ (e.g. LDAP or empty password hash field from the passwd file) that ++ affect the user's login will not be shown in the chage output. ++ ++ ++ The chage program will also not report any ++ inconsistency between the shadow and passwd files (e.g. missing x in ++ the passwd file). The pwck can be used to check ++ for this kind of inconsistencies. ++ + The chage command is restricted to the root + user, except for the option, which may be used by + an unprivileged user to determine when their password or account is due +diff -up shadow-4.6/man/ja/man5/login.defs.5.manfix shadow-4.6/man/ja/man5/login.defs.5 +--- shadow-4.6/man/ja/man5/login.defs.5.manfix 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/man/ja/man5/login.defs.5 2020-10-23 13:15:24.106387639 +0200 +@@ -147,10 +147,6 @@ 以下の参照表は、 + shadow パスワード機能のどのプログラムが + どのパラメータを使用するかを示したものである。 + .na +-.IP chfn 12 +-CHFN_AUTH CHFN_RESTRICT +-.IP chsh 12 +-CHFN_AUTH + .IP groupadd 12 + GID_MAX GID_MIN + .IP newusers 12 +diff -up shadow-4.6/man/login.defs.5.xml.manfix shadow-4.6/man/login.defs.5.xml +--- shadow-4.6/man/login.defs.5.xml.manfix 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/man/login.defs.5.xml 2020-10-23 13:15:43.280475188 +0200 +@@ -162,6 +162,27 @@ + long numeric parameters is machine-dependent. + + ++ ++ Please note that the parameters in this configuration file control the ++ behavior of the tools from the shadow-utils component. None of these ++ tools uses the PAM mechanism, and the utilities that use PAM (such as the ++ passwd command) should be configured elsewhere. The only values that ++ affect PAM modules are ENCRYPT_METHOD and SHA_CRYPT_MAX_ROUNDS ++ for pam_unix module, FAIL_DELAY for pam_faildelay module, ++ and UMASK for pam_umask module. Refer to ++ pam(8) for more information. ++ ++ ++ ++ Please also take into account that this man page is generic and some of ++ the options may be unsupported by currently installed tools. In case of ++ doubt check and ++ . For example see ++ login ++ 1 for login specific options such ++ as LOGIN_STRING. ++ ++ + The following configuration items are provided: + + +@@ -252,16 +273,6 @@ + + + +- chfn +- +- +- CHFN_AUTH +- CHFN_RESTRICT +- LOGIN_STRING +- +- +- +- + chgpasswd + + +@@ -282,14 +293,6 @@ + + + +- +- chsh +- +- +- CHSH_AUTH LOGIN_STRING +- +- +- + + + +@@ -350,34 +353,6 @@ + + + +- +- login +- +- +- CONSOLE +- CONSOLE_GROUPS DEFAULT_HOME +- ENV_HZ ENV_PATH ENV_SUPATH +- ENV_TZ ENVIRON_FILE +- ERASECHAR FAIL_DELAY +- FAILLOG_ENAB +- FAKE_SHELL +- FTMP_FILE +- HUSHLOGIN_FILE +- ISSUE_FILE +- KILLCHAR +- LASTLOG_ENAB +- LOGIN_RETRIES +- LOGIN_STRING +- LOGIN_TIMEOUT LOG_OK_LOGINS LOG_UNKFAIL_ENAB +- MAIL_CHECK_ENAB MAIL_DIR MAIL_FILE +- MOTD_FILE NOLOGINS_FILE PORTTIME_CHECKS_ENAB +- QUOTAS_ENAB +- TTYGROUP TTYPERM TTYTYPE_FILE +- ULIMIT UMASK +- USERGROUPS_ENAB +- +- +- + + + newgrp / sg +@@ -405,17 +380,6 @@ + + + +- +- passwd +- +- +- ENCRYPT_METHOD MD5_CRYPT_ENAB OBSCURE_CHECKS_ENAB +- PASS_ALWAYS_WARN PASS_CHANGE_TRIES PASS_MAX_LEN PASS_MIN_LEN +- SHA_CRYPT_MAX_ROUNDS +- SHA_CRYPT_MIN_ROUNDS +- +- +- + + pwck + +@@ -442,32 +406,6 @@ + + + +- +- su +- +- +- CONSOLE +- CONSOLE_GROUPS DEFAULT_HOME +- ENV_HZ ENVIRON_FILE +- ENV_PATH ENV_SUPATH +- ENV_TZ LOGIN_STRING MAIL_CHECK_ENAB +- MAIL_DIR MAIL_FILE QUOTAS_ENAB +- SULOG_FILE SU_NAME +- SU_WHEEL_ONLY +- SYSLOG_SU_ENAB +- USERGROUPS_ENAB +- +- +- +- +- sulogin +- +- +- ENV_HZ +- ENV_TZ +- +- +- + + useradd + +diff -up shadow-4.6/man/shadow.5.xml.manfix shadow-4.6/man/shadow.5.xml +--- shadow-4.6/man/shadow.5.xml.manfix 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/man/shadow.5.xml 2020-10-23 13:15:24.106387639 +0200 +@@ -129,7 +129,7 @@ + + + The date of the last password change, expressed as the number +- of days since Jan 1, 1970. ++ of days since Jan 1, 1970 00:00 UTC. + + + The value 0 has a special meaning, which is that the user +@@ -208,8 +208,8 @@ + + + After expiration of the password and this expiration period is +- elapsed, no login is possible using the current user's +- password. The user should contact her administrator. ++ elapsed, no login is possible for the user. ++ The user should contact her administrator. + + + An empty field means that there are no enforcement of an +@@ -224,7 +224,7 @@ + + + The date of expiration of the account, expressed as the number +- of days since Jan 1, 1970. ++ of days since Jan 1, 1970 00:00 UTC. + + + Note that an account expiration differs from a password +diff -up shadow-4.6/man/useradd.8.xml.manfix shadow-4.6/man/useradd.8.xml +--- shadow-4.6/man/useradd.8.xml.manfix 2020-10-23 13:15:24.100387611 +0200 ++++ shadow-4.6/man/useradd.8.xml 2020-10-23 13:15:24.106387639 +0200 +@@ -347,6 +347,11 @@ + is not enabled, no home + directories are created. + ++ ++ The directory where the user's home directory is created must ++ exist and have proper SELinux context and permissions. Otherwise ++ the user's home directory cannot be created or accessed. ++ + + + +diff -up shadow-4.6/man/usermod.8.xml.manfix shadow-4.6/man/usermod.8.xml +--- shadow-4.6/man/usermod.8.xml.manfix 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/man/usermod.8.xml 2020-10-23 13:15:24.106387639 +0200 +@@ -132,7 +132,8 @@ + If the + option is given, the contents of the current home directory will + be moved to the new home directory, which is created if it does +- not already exist. ++ not already exist. If the current home directory does not exist ++ the new home directory will not be created. + + + +@@ -256,7 +257,8 @@ + + + Move the content of the user's home directory to the new +- location. ++ location. If the current home directory does not exist ++ the new home directory will not be created. + + + This option is only valid in combination with the +diff -up shadow-4.6/man/login.defs.d/SUB_GID_COUNT.xml.manfix shadow-4.6/man/login.defs.d/SUB_GID_COUNT.xml +--- shadow-4.6/man/login.defs.d/SUB_GID_COUNT.xml.manfix 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/man/login.defs.d/SUB_GID_COUNT.xml 2020-10-23 13:15:24.106387639 +0200 +@@ -42,7 +42,7 @@ + + The default values for , + , +- are respectively 100000, 600100000 and 10000. ++ are respectively 100000, 600100000 and 65536. + + + +diff -up shadow-4.6/man/login.defs.d/SUB_UID_COUNT.xml.manfix shadow-4.6/man/login.defs.d/SUB_UID_COUNT.xml +--- shadow-4.6/man/login.defs.d/SUB_UID_COUNT.xml.manfix 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/man/login.defs.d/SUB_UID_COUNT.xml 2020-10-23 13:15:24.106387639 +0200 +@@ -42,7 +42,7 @@ + + The default values for , + , +- are respectively 100000, 600100000 and 10000. ++ are respectively 100000, 600100000 and 65536. + + + +diff -up shadow-4.6/man/groupadd.8.xml.manfix shadow-4.6/man/groupadd.8.xml +--- shadow-4.6/man/groupadd.8.xml.manfix 2020-10-23 13:15:24.100387611 +0200 ++++ shadow-4.6/man/groupadd.8.xml 2020-10-23 13:15:24.106387639 +0200 +@@ -322,13 +322,13 @@ + + 4 + +- GID not unique (when not used) ++ GID is already used (when called without ) + + + + 9 + +- group name not unique ++ group name is already used + + + diff --git a/SOURCES/shadow-4.6-move-home.patch b/SOURCES/shadow-4.6-move-home.patch new file mode 100644 index 0000000..cff9561 --- /dev/null +++ b/SOURCES/shadow-4.6-move-home.patch @@ -0,0 +1,15 @@ +diff -up shadow-4.6/src/usermod.c.move-home shadow-4.6/src/usermod.c +--- shadow-4.6/src/usermod.c.move-home 2018-05-28 14:59:05.594076665 +0200 ++++ shadow-4.6/src/usermod.c 2018-05-28 15:00:28.479837392 +0200 +@@ -1845,6 +1845,11 @@ static void move_home (void) + Prog, prefix_user_home, prefix_user_newhome); + fail_exit (E_HOMEDIR); + } ++ } else { ++ fprintf (stderr, ++ _("%s: The previous home directory (%s) does " ++ "not exist or is inaccessible. Move cannot be completed.\n"), ++ Prog, prefix_user_home); + } + } + diff --git a/SOURCES/shadow-4.6-orig-context.patch b/SOURCES/shadow-4.6-orig-context.patch new file mode 100644 index 0000000..ea522e7 --- /dev/null +++ b/SOURCES/shadow-4.6-orig-context.patch @@ -0,0 +1,128 @@ +diff -up shadow-4.6/lib/commonio.c.orig-context shadow-4.6/lib/commonio.c +--- shadow-4.6/lib/commonio.c.orig-context 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/lib/commonio.c 2018-05-28 14:56:37.287929667 +0200 +@@ -961,7 +961,7 @@ int commonio_close (struct commonio_db * + snprintf (buf, sizeof buf, "%s-", db->filename); + + #ifdef WITH_SELINUX +- if (set_selinux_file_context (buf) != 0) { ++ if (set_selinux_file_context (buf, db->filename) != 0) { + errors++; + } + #endif +@@ -994,7 +994,7 @@ int commonio_close (struct commonio_db * + snprintf (buf, sizeof buf, "%s+", db->filename); + + #ifdef WITH_SELINUX +- if (set_selinux_file_context (buf) != 0) { ++ if (set_selinux_file_context (buf, db->filename) != 0) { + errors++; + } + #endif +diff -up shadow-4.6/libmisc/copydir.c.orig-context shadow-4.6/libmisc/copydir.c +--- shadow-4.6/libmisc/copydir.c.orig-context 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/libmisc/copydir.c 2018-05-28 14:56:37.287929667 +0200 +@@ -484,7 +484,7 @@ static int copy_dir (const char *src, co + */ + + #ifdef WITH_SELINUX +- if (set_selinux_file_context (dst) != 0) { ++ if (set_selinux_file_context (dst, NULL) != 0) { + return -1; + } + #endif /* WITH_SELINUX */ +@@ -605,7 +605,7 @@ static int copy_symlink (const char *src + } + + #ifdef WITH_SELINUX +- if (set_selinux_file_context (dst) != 0) { ++ if (set_selinux_file_context (dst, NULL) != 0) { + free (oldlink); + return -1; + } +@@ -684,7 +684,7 @@ static int copy_special (const char *src + int err = 0; + + #ifdef WITH_SELINUX +- if (set_selinux_file_context (dst) != 0) { ++ if (set_selinux_file_context (dst, NULL) != 0) { + return -1; + } + #endif /* WITH_SELINUX */ +@@ -744,7 +744,7 @@ static int copy_file (const char *src, c + return -1; + } + #ifdef WITH_SELINUX +- if (set_selinux_file_context (dst) != 0) { ++ if (set_selinux_file_context (dst, NULL) != 0) { + return -1; + } + #endif /* WITH_SELINUX */ +diff -up shadow-4.6/lib/prototypes.h.orig-context shadow-4.6/lib/prototypes.h +--- shadow-4.6/lib/prototypes.h.orig-context 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/lib/prototypes.h 2018-05-28 14:56:37.287929667 +0200 +@@ -326,7 +326,7 @@ extern /*@observer@*/const char *crypt_m + + /* selinux.c */ + #ifdef WITH_SELINUX +-extern int set_selinux_file_context (const char *dst_name); ++extern int set_selinux_file_context (const char *dst_name, const char *orig_name); + extern int reset_selinux_file_context (void); + #endif + +diff -up shadow-4.6/lib/selinux.c.orig-context shadow-4.6/lib/selinux.c +--- shadow-4.6/lib/selinux.c.orig-context 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/lib/selinux.c 2018-05-28 14:56:37.287929667 +0200 +@@ -50,7 +50,7 @@ static bool selinux_enabled; + * Callers may have to Reset SELinux to create files with default + * contexts with reset_selinux_file_context + */ +-int set_selinux_file_context (const char *dst_name) ++int set_selinux_file_context (const char *dst_name, const char *orig_name) + { + /*@null@*/security_context_t scontext = NULL; + +@@ -62,19 +62,23 @@ int set_selinux_file_context (const char + if (selinux_enabled) { + /* Get the default security context for this file */ + if (matchpathcon (dst_name, 0, &scontext) < 0) { +- if (security_getenforce () != 0) { +- return 1; +- } ++ /* We could not get the default, copy the original */ ++ if (orig_name == NULL) ++ goto error; ++ if (getfilecon (orig_name, &scontext) < 0) ++ goto error; + } + /* Set the security context for the next created file */ +- if (setfscreatecon (scontext) < 0) { +- if (security_getenforce () != 0) { +- return 1; +- } +- } ++ if (setfscreatecon (scontext) < 0) ++ goto error; + freecon (scontext); + } + return 0; ++ error: ++ if (security_getenforce () != 0) { ++ return 1; ++ } ++ return 0; + } + + /* +diff -up shadow-4.6/src/useradd.c.orig-context shadow-4.6/src/useradd.c +--- shadow-4.6/src/useradd.c.orig-context 2018-05-28 14:56:37.288929688 +0200 ++++ shadow-4.6/src/useradd.c 2018-05-28 14:58:02.242730903 +0200 +@@ -2020,7 +2020,7 @@ static void create_home (void) + { + if (access (prefix_user_home, F_OK) != 0) { + #ifdef WITH_SELINUX +- if (set_selinux_file_context (prefix_user_home) != 0) { ++ if (set_selinux_file_context (prefix_user_home, NULL) != 0) { + fprintf (stderr, + _("%s: cannot set SELinux context for home directory %s\n"), + Prog, user_home); diff --git a/SOURCES/shadow-4.6-redhat.patch b/SOURCES/shadow-4.6-redhat.patch new file mode 100644 index 0000000..7a8be2e --- /dev/null +++ b/SOURCES/shadow-4.6-redhat.patch @@ -0,0 +1,41 @@ +diff -up shadow-4.6/src/useradd.c.redhat shadow-4.6/src/useradd.c +--- shadow-4.6/src/useradd.c.redhat 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/src/useradd.c 2018-05-28 13:37:16.695651258 +0200 +@@ -98,7 +98,7 @@ const char *Prog; + static gid_t def_group = 100; + static const char *def_gname = "other"; + static const char *def_home = "/home"; +-static const char *def_shell = ""; ++static const char *def_shell = "/sbin/nologin"; + static const char *def_template = SKEL_DIR; + static const char *def_create_mail_spool = "no"; + +@@ -108,7 +108,7 @@ static const char *def_expire = ""; + #define VALID(s) (strcspn (s, ":\n") == strlen (s)) + + static const char *user_name = ""; +-static const char *user_pass = "!"; ++static const char *user_pass = "!!"; + static uid_t user_id; + static gid_t user_gid; + static const char *user_comment = ""; +@@ -1114,9 +1114,9 @@ static void process_flags (int argc, cha + }; + while ((c = getopt_long (argc, argv, + #ifdef WITH_SELINUX +- "b:c:d:De:f:g:G:hk:K:lmMNop:rR:P:s:u:UZ:", ++ "b:c:d:De:f:g:G:hk:K:lmMnNop:rR:P:s:u:UZ:", + #else /* !WITH_SELINUX */ +- "b:c:d:De:f:g:G:hk:K:lmMNop:rR:P:s:u:U", ++ "b:c:d:De:f:g:G:hk:K:lmMnNop:rR:P:s:u:U", + #endif /* !WITH_SELINUX */ + long_options, NULL)) != -1) { + switch (c) { +@@ -1267,6 +1267,7 @@ static void process_flags (int argc, cha + case 'M': + Mflg = true; + break; ++ case 'n': + case 'N': + Nflg = true; + break; diff --git a/SOURCES/shadow-4.6-regular-user.patch b/SOURCES/shadow-4.6-regular-user.patch new file mode 100644 index 0000000..a1c781a --- /dev/null +++ b/SOURCES/shadow-4.6-regular-user.patch @@ -0,0 +1,108 @@ +From fd4405b763d26649339069532e79bd45013c8c38 Mon Sep 17 00:00:00 2001 +From: Tomas Mraz +Date: Mon, 20 Jan 2020 13:58:07 +0100 +Subject: [PATCH] Do not mistake a regular user process for a namespaced one + +In case there is a regular user with a process running on a system +with uid falling into a namespaced uid range of another user. +The user with the colliding namespaced uid range will not be +allowed to be deleted without forcing the action with -f. + +The user_busy() is adjusted to check whether the suspected process +is really a namespaced process in a different namespace. +--- + libmisc/user_busy.c | 44 ++++++++++++++++++++++++++++++++++++-------- + 1 file changed, 36 insertions(+), 8 deletions(-) + +diff --git a/libmisc/user_busy.c b/libmisc/user_busy.c +index b0867568..324bb946 100644 +--- a/libmisc/user_busy.c ++++ b/libmisc/user_busy.c +@@ -39,6 +39,7 @@ + #include + #include + #include ++#include + #include "defines.h" + #include "prototypes.h" + #ifdef ENABLE_SUBIDS +@@ -106,6 +107,31 @@ static int user_busy_utmp (const char *name) + #endif /* !__linux__ */ + + #ifdef __linux__ ++#ifdef ENABLE_SUBIDS ++#define in_parentuid_range(uid) ((uid) >= parentuid && (uid) < parentuid + range) ++static int different_namespace (const char *sname) ++{ ++ /* 41: /proc/xxxxxxxxxx/task/xxxxxxxxxx/ns/user + \0 */ ++ char path[41]; ++ char buf[512], buf2[512]; ++ ssize_t llen1, llen2; ++ ++ snprintf (path, 41, "/proc/%s/ns/user", sname); ++ ++ if ((llen1 = readlink (path, buf, sizeof(buf))) == -1) ++ return 0; ++ ++ if ((llen2 = readlink ("/proc/self/ns/user", buf2, sizeof(buf2))) == -1) ++ return 0; ++ ++ if (llen1 == llen2 && memcmp (buf, buf2, llen1) == 0) ++ return 0; /* same namespace */ ++ ++ return 1; ++} ++#endif /* ENABLE_SUBIDS */ ++ ++ + static int check_status (const char *name, const char *sname, uid_t uid) + { + /* 40: /proc/xxxxxxxxxx/task/xxxxxxxxxx/status + \0 */ +@@ -114,7 +140,6 @@ static int check_status (const char *name, const char *sname, uid_t uid) + FILE *sfile; + + snprintf (status, 40, "/proc/%s/status", sname); +- status[39] = '\0'; + + sfile = fopen (status, "r"); + if (NULL == sfile) { +@@ -123,26 +148,29 @@ static int check_status (const char *name, const char *sname, uid_t uid) + while (fgets (line, sizeof (line), sfile) == line) { + if (strncmp (line, "Uid:\t", 5) == 0) { + unsigned long ruid, euid, suid; ++ + assert (uid == (unsigned long) uid); ++ (void) fclose (sfile); + if (sscanf (line, + "Uid:\t%lu\t%lu\t%lu\n", + &ruid, &euid, &suid) == 3) { + if ( (ruid == (unsigned long) uid) + || (euid == (unsigned long) uid) +- || (suid == (unsigned long) uid) ++ || (suid == (unsigned long) uid) ) { ++ return 1; ++ } + #ifdef ENABLE_SUBIDS +- || have_sub_uids(name, ruid, 1) +- || have_sub_uids(name, euid, 1) +- || have_sub_uids(name, suid, 1) +-#endif /* ENABLE_SUBIDS */ ++ if ( different_namespace (sname) ++ && ( have_sub_uids(name, ruid, 1) ++ || have_sub_uids(name, euid, 1) ++ || have_sub_uids(name, suid, 1)) + ) { +- (void) fclose (sfile); + return 1; + } ++#endif /* ENABLE_SUBIDS */ + } else { + /* Ignore errors. This is just a best effort. */ + } +- (void) fclose (sfile); + return 0; + } + } +-- +2.25.2 + diff --git a/SOURCES/shadow-4.6-remove-login-string-references.patch b/SOURCES/shadow-4.6-remove-login-string-references.patch new file mode 100644 index 0000000..eccf9c6 --- /dev/null +++ b/SOURCES/shadow-4.6-remove-login-string-references.patch @@ -0,0 +1,19 @@ +diff -up shadow-4.6/man/login.defs.5.xml.remove_login_string_references shadow-4.6/man/login.defs.5.xml +--- shadow-4.6/man/login.defs.5.xml.remove_login_string_references 2021-04-27 13:01:49.428338258 +0200 ++++ shadow-4.6/man/login.defs.5.xml 2021-04-27 13:01:49.433338329 +0200 +@@ -58,7 +58,6 @@ + + + +- + + + +@@ -214,7 +213,6 @@ + &LOG_OK_LOGINS; + &LOG_UNKFAIL_ENAB; + &LOGIN_RETRIES; +- &LOGIN_STRING; + &LOGIN_TIMEOUT; + &MAIL_CHECK_ENAB; + &MAIL_DIR; diff --git a/SOURCES/shadow-4.6-respect_enable_static_no.patch b/SOURCES/shadow-4.6-respect_enable_static_no.patch new file mode 100644 index 0000000..ed62a08 --- /dev/null +++ b/SOURCES/shadow-4.6-respect_enable_static_no.patch @@ -0,0 +1,24 @@ +diff -up shadow-4.6/configure.ac.respect_enable_static_no shadow-4.6/configure.ac +--- shadow-4.6/configure.ac.respect_enable_static_no 2021-11-03 12:09:39.852829632 +0100 ++++ shadow-4.6/configure.ac 2021-11-03 12:10:32.447203434 +0100 +@@ -311,6 +311,8 @@ if test "$with_sha_crypt" = "yes"; then + AC_DEFINE(USE_SHA_CRYPT, 1, [Define to allow the SHA256 and SHA512 password encryption algorithms]) + fi + ++AM_CONDITIONAL(ENABLE_SHARED, test "x$enable_shared" = "xyes") ++ + if test "$with_nscd" = "yes"; then + AC_CHECK_FUNC(posix_spawn, + [AC_DEFINE(USE_NSCD, 1, [Define to support flushing of nscd caches])], +diff -up shadow-4.6/libsubid/Makefile.am.respect_enable_static_no shadow-4.6/libsubid/Makefile.am +--- shadow-4.6/libsubid/Makefile.am.respect_enable_static_no 2021-11-03 12:09:39.851829625 +0100 ++++ shadow-4.6/libsubid/Makefile.am 2021-11-03 12:09:39.852829632 +0100 +@@ -1,6 +1,8 @@ + lib_LTLIBRARIES = libsubid.la ++if ENABLE_SHARED + libsubid_la_LDFLAGS = -Wl,-soname,libsubid.so.@LIBSUBID_ABI@ \ + -shared -version-info @LIBSUBID_ABI_MAJOR@ ++endif + libsubid_la_SOURCES = api.c + + pkginclude_HEADERS = subid.h diff --git a/SOURCES/shadow-4.6-salt-remove-rounds.patch b/SOURCES/shadow-4.6-salt-remove-rounds.patch new file mode 100644 index 0000000..48439be --- /dev/null +++ b/SOURCES/shadow-4.6-salt-remove-rounds.patch @@ -0,0 +1,15 @@ +diff --git a/libmisc/salt.c b/libmisc/salt.c +index c72447ea..4940d76e 100644 +--- a/libmisc/salt.c ++++ b/libmisc/salt.c +@@ -248,6 +248,10 @@ static /*@observer@*/const char *gensalt (size_t salt_size) + result[0] = '\0'; + } + ++ if (strstr(result, "rounds=") != NULL) { ++ result[3] = '\0'; ++ } ++ + /* + * Concatenate a pseudo random salt. + */ diff --git a/SOURCES/shadow-4.6-selinux-perms.patch b/SOURCES/shadow-4.6-selinux-perms.patch new file mode 100644 index 0000000..977f3c9 --- /dev/null +++ b/SOURCES/shadow-4.6-selinux-perms.patch @@ -0,0 +1,284 @@ +diff -up shadow-4.8/src/chgpasswd.c.selinux-perms shadow-4.8/src/chgpasswd.c +--- shadow-4.8/src/chgpasswd.c.selinux-perms 2019-12-01 18:02:43.000000000 +0100 ++++ shadow-4.8/src/chgpasswd.c 2020-01-13 10:21:44.558107260 +0100 +@@ -39,6 +39,13 @@ + #include + #include + #include ++#ifdef WITH_SELINUX ++#include ++#include ++#endif ++#ifdef WITH_LIBAUDIT ++#include ++#endif + #ifdef ACCT_TOOLS_SETUID + #ifdef USE_PAM + #include "pam_defs.h" +@@ -80,6 +87,9 @@ static bool sgr_locked = false; + #endif + static bool gr_locked = false; + ++/* The name of the caller */ ++static char *myname = NULL; ++ + /* local function prototypes */ + static void fail_exit (int code); + static /*@noreturn@*/void usage (int status); +@@ -334,6 +344,63 @@ static void check_perms (void) + #endif /* ACCT_TOOLS_SETUID */ + } + ++#ifdef WITH_SELINUX ++static int ++log_callback (int type, const char *fmt, ...) ++{ ++ int audit_fd; ++ va_list ap; ++ ++ va_start(ap, fmt); ++#ifdef WITH_AUDIT ++ audit_fd = audit_open(); ++ ++ if (audit_fd >= 0) { ++ char *buf; ++ ++ if (vasprintf (&buf, fmt, ap) < 0) ++ goto ret; ++ audit_log_user_avc_message(audit_fd, AUDIT_USER_AVC, buf, NULL, NULL, ++ NULL, 0); ++ audit_close(audit_fd); ++ free(buf); ++ goto ret; ++ } ++ ++#endif ++ vsyslog (LOG_USER | LOG_INFO, fmt, ap); ++ret: ++ va_end(ap); ++ return 0; ++} ++ ++static void ++selinux_check_root (void) ++{ ++ int status = -1; ++ security_context_t user_context; ++ union selinux_callback old_callback; ++ ++ if (is_selinux_enabled() < 1) ++ return; ++ ++ old_callback = selinux_get_callback(SELINUX_CB_LOG); ++ /* setup callbacks */ ++ selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback) &log_callback); ++ if ((status = getprevcon(&user_context)) < 0) { ++ selinux_set_callback(SELINUX_CB_LOG, old_callback); ++ exit(1); ++ } ++ ++ status = selinux_check_access(user_context, user_context, "passwd", "passwd", NULL); ++ ++ selinux_set_callback(SELINUX_CB_LOG, old_callback); ++ freecon(user_context); ++ if (status != 0 && security_getenforce() != 0) ++ exit(1); ++} ++#endif ++ + /* + * open_files - lock and open the group databases + */ +@@ -427,6 +494,7 @@ int main (int argc, char **argv) + + const struct group *gr; + struct group newgr; ++ struct passwd *pw = NULL; + int errors = 0; + int line = 0; + +@@ -436,12 +504,37 @@ int main (int argc, char **argv) + (void) bindtextdomain (PACKAGE, LOCALEDIR); + (void) textdomain (PACKAGE); + ++#ifdef WITH_SELINUX ++ selinux_check_root (); ++#endif ++ + process_root_flag ("-R", argc, argv); + + process_flags (argc, argv); + + OPENLOG ("chgpasswd"); + ++#ifdef WITH_AUDIT ++ audit_help_open (); ++#endif ++ ++ /* ++ * Determine the name of the user that invoked this command. This ++ * is really hit or miss because there are so many ways that command ++ * can be executed and so many ways to trip up the routines that ++ * report the user name. ++ */ ++ pw = get_my_pwent (); ++ if (NULL == pw) { ++ fprintf (stderr, _("%s: Cannot determine your user name.\n"), ++ Prog); ++ SYSLOG ((LOG_WARN, ++ "Cannot determine the user name of the caller (UID %lu)", ++ (unsigned long) getuid ())); ++ exit (E_NOPERM); ++ } ++ myname = xstrdup (pw->pw_name); ++ + check_perms (); + + #ifdef SHADOWGRP +@@ -536,6 +629,15 @@ int main (int argc, char **argv) + newgr.gr_passwd = cp; + } + ++#ifdef WITH_AUDIT ++ { ++ ++ audit_logger_with_group (AUDIT_GRP_CHAUTHTOK, Prog, ++ "change-password", ++ myname, AUDIT_NO_ID, gr->gr_name, ++ SHADOW_AUDIT_SUCCESS); ++ } ++#endif + /* + * The updated group file entry is then put back and will + * be written to the group file later, after all the +diff -up shadow-4.8/src/chpasswd.c.selinux-perms shadow-4.8/src/chpasswd.c +--- shadow-4.8/src/chpasswd.c.selinux-perms 2019-12-01 18:02:43.000000000 +0100 ++++ shadow-4.8/src/chpasswd.c 2020-01-13 10:21:44.558107260 +0100 +@@ -39,6 +39,13 @@ + #include + #include + #include ++#ifdef WITH_SELINUX ++#include ++#include ++#endif ++#ifdef WITH_LIBAUDIT ++#include ++#endif + #ifdef USE_PAM + #include "pam_defs.h" + #endif /* USE_PAM */ +@@ -332,6 +339,63 @@ static void check_perms (void) + #endif /* USE_PAM */ + } + ++#ifdef WITH_SELINUX ++static int ++log_callback (int type, const char *fmt, ...) ++{ ++ int audit_fd; ++ va_list ap; ++ ++ va_start(ap, fmt); ++#ifdef WITH_AUDIT ++ audit_fd = audit_open(); ++ ++ if (audit_fd >= 0) { ++ char *buf; ++ ++ if (vasprintf (&buf, fmt, ap) < 0) ++ goto ret; ++ audit_log_user_avc_message(audit_fd, AUDIT_USER_AVC, buf, NULL, NULL, ++ NULL, 0); ++ audit_close(audit_fd); ++ free(buf); ++ goto ret; ++ } ++ ++#endif ++ vsyslog (LOG_USER | LOG_INFO, fmt, ap); ++ret: ++ va_end(ap); ++ return 0; ++} ++ ++static void ++selinux_check_root (void) ++{ ++ int status = -1; ++ security_context_t user_context; ++ union selinux_callback old_callback; ++ ++ if (is_selinux_enabled() < 1) ++ return; ++ ++ old_callback = selinux_get_callback(SELINUX_CB_LOG); ++ /* setup callbacks */ ++ selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback) &log_callback); ++ if ((status = getprevcon(&user_context)) < 0) { ++ selinux_set_callback(SELINUX_CB_LOG, old_callback); ++ exit(1); ++ } ++ ++ status = selinux_check_access(user_context, user_context, "passwd", "passwd", NULL); ++ ++ selinux_set_callback(SELINUX_CB_LOG, old_callback); ++ freecon(user_context); ++ if (status != 0 && security_getenforce() != 0) ++ exit(1); ++} ++#endif ++ + /* + * open_files - lock and open the password databases + */ +@@ -428,6 +492,10 @@ int main (int argc, char **argv) + (void) bindtextdomain (PACKAGE, LOCALEDIR); + (void) textdomain (PACKAGE); + ++#ifdef WITH_SELINUX ++ selinux_check_root (); ++#endif ++ + process_root_flag ("-R", argc, argv); + + process_flags (argc, argv); +@@ -440,6 +508,10 @@ int main (int argc, char **argv) + + OPENLOG ("chpasswd"); + ++#ifdef WITH_AUDIT ++ audit_help_open (); ++#endif ++ + check_perms (); + + #ifdef USE_PAM +@@ -566,6 +638,11 @@ int main (int argc, char **argv) + newpw.pw_passwd = cp; + } + ++#ifdef WITH_AUDIT ++ audit_logger (AUDIT_USER_CHAUTHTOK, Prog, ++ "updating-password", ++ pw->pw_name, (unsigned int) pw->pw_uid, 1); ++#endif + /* + * The updated password file entry is then put back and will + * be written to the password file later, after all the +Index: shadow-4.5/src/Makefile.am +=================================================================== +--- shadow-4.5.orig/src/Makefile.am ++++ shadow-4.5/src/Makefile.am +@@ -87,9 +87,9 @@ chage_LDADD = $(LDADD) $(LIBPAM_SUID) + newuidmap_LDADD = $(LDADD) $(LIBSELINUX) + newgidmap_LDADD = $(LDADD) $(LIBSELINUX) + chfn_LDADD = $(LDADD) $(LIBPAM) $(LIBSELINUX) $(LIBCRYPT_NOPAM) $(LIBSKEY) $(LIBMD) +-chgpasswd_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBSELINUX) $(LIBCRYPT) ++chgpasswd_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBSELINUX) $(LIBAUDIT) $(LIBCRYPT) + chsh_LDADD = $(LDADD) $(LIBPAM) $(LIBSELINUX) $(LIBCRYPT_NOPAM) $(LIBSKEY) $(LIBMD) +-chpasswd_LDADD = $(LDADD) $(LIBPAM) $(LIBSELINUX) $(LIBCRYPT) ++chpasswd_LDADD = $(LDADD) $(LIBPAM) $(LIBSELINUX) $(LIBAUDIT) $(LIBCRYPT) + gpasswd_LDADD = $(LDADD) $(LIBAUDIT) $(LIBSELINUX) $(LIBCRYPT) + groupadd_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) + groupdel_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) diff --git a/SOURCES/shadow-4.6-selinux.patch b/SOURCES/shadow-4.6-selinux.patch new file mode 100644 index 0000000..dfd5140 --- /dev/null +++ b/SOURCES/shadow-4.6-selinux.patch @@ -0,0 +1,115 @@ +diff -up shadow-4.6/lib/semanage.c.selinux shadow-4.6/lib/semanage.c +--- shadow-4.6/lib/semanage.c.selinux 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/lib/semanage.c 2018-05-28 13:38:20.551008911 +0200 +@@ -294,6 +294,9 @@ int set_seuser (const char *login_name, + + ret = 0; + ++ /* drop obsolete matchpathcon cache */ ++ matchpathcon_fini(); ++ + done: + semanage_seuser_key_free (key); + semanage_handle_destroy (handle); +@@ -369,6 +372,10 @@ int del_seuser (const char *login_name) + } + + ret = 0; ++ ++ /* drop obsolete matchpathcon cache */ ++ matchpathcon_fini(); ++ + done: + semanage_handle_destroy (handle); + return ret; +diff -up shadow-4.6/src/useradd.c.selinux shadow-4.6/src/useradd.c +--- shadow-4.6/src/useradd.c.selinux 2018-05-28 13:43:30.996748997 +0200 ++++ shadow-4.6/src/useradd.c 2018-05-28 13:44:04.645486199 +0200 +@@ -2120,6 +2120,7 @@ static void create_mail (void) + */ + int main (int argc, char **argv) + { ++ int rv = E_SUCCESS; + #ifdef ACCT_TOOLS_SETUID + #ifdef USE_PAM + pam_handle_t *pamh = NULL; +@@ -2342,27 +2343,11 @@ int main (int argc, char **argv) + + usr_update (); + +- if (mflg) { +- create_home (); +- if (home_added) { +- copy_tree (def_template, prefix_user_home, false, false, +- (uid_t)-1, user_id, (gid_t)-1, user_gid); +- } else { +- fprintf (stderr, +- _("%s: warning: the home directory already exists.\n" +- "Not copying any file from skel directory into it.\n"), +- Prog); +- } +- +- } +- +- /* Do not create mail directory for system accounts */ +- if (!rflg) { +- create_mail (); +- } +- + close_files (); + ++ nscd_flush_cache ("passwd"); ++ nscd_flush_cache ("group"); ++ + /* + * tallylog_reset needs to be able to lookup + * a valid existing user name, +@@ -2373,8 +2358,9 @@ int main (int argc, char **argv) + } + + #ifdef WITH_SELINUX +- if (Zflg) { +- if (set_seuser (user_name, user_selinux) != 0) { ++ if (Zflg && *user_selinux) { ++ if (is_selinux_enabled () > 0) { ++ if (set_seuser (user_name, user_selinux) != 0) { + fprintf (stderr, + _("%s: warning: the user name %s to %s SELinux user mapping failed.\n"), + Prog, user_name, user_selinux); +@@ -2383,14 +2369,31 @@ int main (int argc, char **argv) + "adding SELinux user mapping", + user_name, (unsigned int) user_id, 0); + #endif /* WITH_AUDIT */ +- fail_exit (E_SE_UPDATE); ++ rv = E_SE_UPDATE; ++ } + } + } +-#endif /* WITH_SELINUX */ ++#endif + +- nscd_flush_cache ("passwd"); +- nscd_flush_cache ("group"); ++ if (mflg) { ++ create_home (); ++ if (home_added) { ++ copy_tree (def_template, prefix_user_home, false, true, ++ (uid_t)-1, user_id, (gid_t)-1, user_gid); ++ } else { ++ fprintf (stderr, ++ _("%s: warning: the home directory already exists.\n" ++ "Not copying any file from skel directory into it.\n"), ++ Prog); ++ } ++ ++ } ++ ++ /* Do not create mail directory for system accounts */ ++ if (!rflg) { ++ create_mail (); ++ } + +- return E_SUCCESS; ++ return rv; + } + diff --git a/SOURCES/shadow-4.6-skip-over-reserved-ids.patch b/SOURCES/shadow-4.6-skip-over-reserved-ids.patch new file mode 100644 index 0000000..efce55a --- /dev/null +++ b/SOURCES/shadow-4.6-skip-over-reserved-ids.patch @@ -0,0 +1,214 @@ +From baae5b4a06c905d9f52ed1f922a0d7d0625d11cf Mon Sep 17 00:00:00 2001 +From: Martin Kletzander +Date: Wed, 1 Feb 2023 15:36:41 +0100 +Subject: [PATCH] find_new_[gu]id(): Skip over IDs that are reserved for legacy + reasons + +Some programs don't support `(uint16_t) -1` or `(uint32_t) -1` as user +or group IDs. This is because `-1` is used as an error code or as an +unspecified ID, e.g. in `chown(2)` parameters, and in the past, `gid_t` +and `uid_t` have changed width. For legacy reasons, those values have +been kept reserved in programs today (for example systemd does this; see +the documentation in the link below). + +This should not be confused with catching overflow in the ID values, +since that is already caught by our ERANGE checks. This is about not +using reserved values that have been reserved for legacy reasons. + +Link: +Reviewed-by: Alejandro Colomar +Signed-off-by: Martin Kletzander +--- + libmisc/find_new_gid.c | 38 ++++++++++++++++++++++++++++---------- + libmisc/find_new_uid.c | 38 ++++++++++++++++++++++++++++---------- + 2 files changed, 56 insertions(+), 20 deletions(-) + +diff --git a/libmisc/find_new_gid.c b/libmisc/find_new_gid.c +index 70ba95a2..da1d8d55 100644 +--- a/libmisc/find_new_gid.c ++++ b/libmisc/find_new_gid.c +@@ -98,6 +98,7 @@ static int get_ranges (bool sys_group, gid_t *min_id, gid_t *max_id, + * + * On success, return 0 + * If the ID is in use, return EEXIST ++ * If the ID might clash with -1, return EINVAL + * If the ID is outside the range, return ERANGE + * In other cases, return errno from getgrgid() + */ +@@ -111,6 +112,11 @@ static int check_gid (const gid_t gid, + return ERANGE; + } + ++ /* Check for compatibility with 16b and 32b gid_t error codes */ ++ if (gid == UINT16_MAX || gid == UINT32_MAX) { ++ return EINVAL; ++ } ++ + /* + * Check whether we already detected this GID + * using the gr_next() loop +@@ -182,10 +188,10 @@ int find_new_gid (bool sys_group, + * gr_locate_gid() found the GID in an as-yet uncommitted + * entry. We'll proceed below and auto-set a GID. + */ +- } else if (result == EEXIST || result == ERANGE) { ++ } else if (result == EEXIST || result == ERANGE || result == EINVAL) { + /* + * Continue on below. At this time, we won't +- * treat these two cases differently. ++ * treat these three cases differently. + */ + } else { + /* +@@ -296,8 +302,11 @@ int find_new_gid (bool sys_group, + *gid = id; + free (used_gids); + return 0; +- } else if (result == EEXIST) { +- /* This GID is in use, we'll continue to the next */ ++ } else if (result == EEXIST || result == EINVAL) { ++ /* ++ * This GID is in use or unusable, we'll ++ * continue to the next. ++ */ + } else { + /* + * An unexpected error occurred. +@@ -339,8 +348,11 @@ int find_new_gid (bool sys_group, + *gid = id; + free (used_gids); + return 0; +- } else if (result == EEXIST) { +- /* This GID is in use, we'll continue to the next */ ++ } else if (result == EEXIST || result == EINVAL) { ++ /* ++ * This GID is in use or unusable, we'll ++ * continue to the next. ++ */ + } else { + /* + * An unexpected error occurred. +@@ -399,8 +411,11 @@ int find_new_gid (bool sys_group, + *gid = id; + free (used_gids); + return 0; +- } else if (result == EEXIST) { +- /* This GID is in use, we'll continue to the next */ ++ } else if (result == EEXIST || result == EINVAL) { ++ /* ++ * This GID is in use or unusable, we'll ++ * continue to the next. ++ */ + } else { + /* + * An unexpected error occurred. +@@ -442,8 +457,11 @@ int find_new_gid (bool sys_group, + *gid = id; + free (used_gids); + return 0; +- } else if (result == EEXIST) { +- /* This GID is in use, we'll continue to the next */ ++ } else if (result == EEXIST || result == EINVAL) { ++ /* ++ * This GID is in use or unusable, we'll ++ * continue to the next. ++ */ + } else { + /* + * An unexpected error occurred. +diff --git a/libmisc/find_new_uid.c b/libmisc/find_new_uid.c +index 6b71dfe5..09885236 100644 +--- a/libmisc/find_new_uid.c ++++ b/libmisc/find_new_uid.c +@@ -98,6 +98,7 @@ static int get_ranges (bool sys_user, uid_t *min_id, uid_t *max_id, + * + * On success, return 0 + * If the ID is in use, return EEXIST ++ * If the ID might clash with -1, return EINVAL + * If the ID is outside the range, return ERANGE + * In other cases, return errno from getpwuid() + */ +@@ -111,6 +112,11 @@ static int check_uid(const uid_t uid, + return ERANGE; + } + ++ /* Check for compatibility with 16b and 32b uid_t error codes */ ++ if (uid == UINT16_MAX || uid == UINT32_MAX) { ++ return EINVAL; ++ } ++ + /* + * Check whether we already detected this UID + * using the pw_next() loop +@@ -182,10 +188,10 @@ int find_new_uid(bool sys_user, + * pw_locate_uid() found the UID in an as-yet uncommitted + * entry. We'll proceed below and auto-set an UID. + */ +- } else if (result == EEXIST || result == ERANGE) { ++ } else if (result == EEXIST || result == ERANGE || result == EINVAL) { + /* + * Continue on below. At this time, we won't +- * treat these two cases differently. ++ * treat these three cases differently. + */ + } else { + /* +@@ -296,8 +302,11 @@ int find_new_uid(bool sys_user, + *uid = id; + free (used_uids); + return 0; +- } else if (result == EEXIST) { +- /* This UID is in use, we'll continue to the next */ ++ } else if (result == EEXIST || result == EINVAL) { ++ /* ++ * This GID is in use or unusable, we'll ++ * continue to the next. ++ */ + } else { + /* + * An unexpected error occurred. +@@ -339,8 +348,11 @@ int find_new_uid(bool sys_user, + *uid = id; + free (used_uids); + return 0; +- } else if (result == EEXIST) { +- /* This UID is in use, we'll continue to the next */ ++ } else if (result == EEXIST || result == EINVAL) { ++ /* ++ * This GID is in use or unusable, we'll ++ * continue to the next. ++ */ + } else { + /* + * An unexpected error occurred. +@@ -399,8 +411,11 @@ int find_new_uid(bool sys_user, + *uid = id; + free (used_uids); + return 0; +- } else if (result == EEXIST) { +- /* This UID is in use, we'll continue to the next */ ++ } else if (result == EEXIST || result == EINVAL) { ++ /* ++ * This GID is in use or unusable, we'll ++ * continue to the next. ++ */ + } else { + /* + * An unexpected error occurred. +@@ -442,8 +457,11 @@ int find_new_uid(bool sys_user, + *uid = id; + free (used_uids); + return 0; +- } else if (result == EEXIST) { +- /* This UID is in use, we'll continue to the next */ ++ } else if (result == EEXIST || result == EINVAL) { ++ /* ++ * This GID is in use or unusable, we'll ++ * continue to the next. ++ */ + } else { + /* + * An unexpected error occurred. +-- +2.40.1 + diff --git a/SOURCES/shadow-4.6-sssd-flush.patch b/SOURCES/shadow-4.6-sssd-flush.patch new file mode 100644 index 0000000..025c1d3 --- /dev/null +++ b/SOURCES/shadow-4.6-sssd-flush.patch @@ -0,0 +1,641 @@ +From 4aaf05d72e9d6daf348cefb8a6ad35d2966cbe9b Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Wed, 12 Sep 2018 14:22:11 +0200 +Subject: [PATCH] Flush sssd caches in addition to nscd caches + +Some distributions, notably Fedora, have the following order of nsswitch +modules by default: + passwd: sss files + group: sss files + +The advantage of serving local users through SSSD is that the nss_sss +module has a fast mmapped-cache that speeds up NSS lookups compared to +accessing the disk an opening the files on each NSS request. + +Traditionally, this has been done with the help of nscd, but using nscd +in parallel with sssd is cumbersome, as both SSSD and nscd use their own +independent caching, so using nscd in setups where sssd is also serving +users from some remote domain (LDAP, AD, ...) can result in a bit of +unpredictability. + +More details about why Fedora chose to use sss before files can be found +on e.g.: + https://fedoraproject.org//wiki/Changes/SSSDCacheForLocalUsers +or: + https://docs.pagure.org/SSSD.sssd/design_pages/files_provider.html + +Now, even though sssd watches the passwd and group files with the help +of inotify, there can still be a small window where someone requests a +user or a group, finds that it doesn't exist, adds the entry and checks +again. Without some support in shadow-utils that would explicitly drop +the sssd caches, the inotify watch can fire a little late, so a +combination of commands like this: + getent passwd user || useradd user; getent passwd user +can result in the second getent passwd not finding the newly added user +as the racy behaviour might still return the cached negative hit from +the first getent passwd. + +This patch more or less copies the already existing support that +shadow-utils had for dropping nscd caches, except using the "sss_cache" +tool that sssd ships. +--- + configure.ac | 10 +++++++ + lib/Makefile.am | 2 ++ + lib/commonio.c | 2 ++ + lib/sssd.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++ + lib/sssd.h | 17 +++++++++++ + src/chfn.c | 2 ++ + src/chgpasswd.c | 2 ++ + src/chpasswd.c | 2 ++ + src/chsh.c | 2 ++ + src/gpasswd.c | 2 ++ + src/groupadd.c | 2 ++ + src/groupdel.c | 2 ++ + src/groupmod.c | 2 ++ + src/grpck.c | 2 ++ + src/grpconv.c | 2 ++ + src/grpunconv.c | 2 ++ + src/newusers.c | 2 ++ + src/passwd.c | 2 ++ + src/pwck.c | 2 ++ + src/pwconv.c | 2 ++ + src/pwunconv.c | 2 ++ + src/useradd.c | 2 ++ + src/userdel.c | 2 ++ + src/usermod.c | 2 ++ + src/vipw.c | 2 ++ + 25 files changed, 146 insertions(+) + create mode 100644 lib/sssd.c + create mode 100644 lib/sssd.h + +diff --git a/configure.ac b/configure.ac +index 41068a5d..10ad70cf 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -280,6 +280,9 @@ AC_ARG_WITH(sha-crypt, + AC_ARG_WITH(nscd, + [AC_HELP_STRING([--with-nscd], [enable support for nscd @<:@default=yes@:>@])], + [with_nscd=$withval], [with_nscd=yes]) ++AC_ARG_WITH(sssd, ++ [AC_HELP_STRING([--with-sssd], [enable support for flushing sssd caches @<:@default=yes@:>@])], ++ [with_sssd=$withval], [with_sssd=yes]) + AC_ARG_WITH(group-name-max-length, + [AC_HELP_STRING([--with-group-name-max-length], [set max group name length @<:@default=16@:>@])], + [with_group_name_max_length=$withval], [with_group_name_max_length=yes]) +@@ -304,6 +307,12 @@ if test "$with_nscd" = "yes"; then + [AC_MSG_ERROR([posix_spawn is needed for nscd support])]) + fi + ++if test "$with_sssd" = "yes"; then ++ AC_CHECK_FUNC(posix_spawn, ++ [AC_DEFINE(USE_SSSD, 1, [Define to support flushing of sssd caches])], ++ [AC_MSG_ERROR([posix_spawn is needed for sssd support])]) ++fi ++ + dnl Check for some functions in libc first, only if not found check for + dnl other libraries. This should prevent linking libnsl if not really + dnl needed (Linux glibc, Irix), but still link it if needed (Solaris). +@@ -679,5 +688,6 @@ echo " shadow group support: $enable_shadowgrp" + echo " S/Key support: $with_skey" + echo " SHA passwords encryption: $with_sha_crypt" + echo " nscd support: $with_nscd" ++echo " sssd support: $with_sssd" + echo " subordinate IDs support: $enable_subids" + echo +diff --git a/lib/Makefile.am b/lib/Makefile.am +index 6db86cd6..fd634542 100644 +--- a/lib/Makefile.am ++++ b/lib/Makefile.am +@@ -30,6 +30,8 @@ libshadow_la_SOURCES = \ + lockpw.c \ + nscd.c \ + nscd.h \ ++ sssd.c \ ++ sssd.h \ + pam_defs.h \ + port.c \ + port.h \ +diff --git a/lib/commonio.c b/lib/commonio.c +index d06b8e7d..96f2d5f7 100644 +--- a/lib/commonio.c ++++ b/lib/commonio.c +@@ -45,6 +45,7 @@ + #include + #include + #include "nscd.h" ++#include "sssd.h" + #ifdef WITH_TCB + #include + #endif /* WITH_TCB */ +@@ -485,6 +486,7 @@ static void dec_lock_count (void) + if (nscd_need_reload) { + nscd_flush_cache ("passwd"); + nscd_flush_cache ("group"); ++ sssd_flush_cache (SSSD_DB_PASSWD | SSSD_DB_GROUP); + nscd_need_reload = false; + } + #ifdef HAVE_LCKPWDF +diff --git a/lib/sssd.c b/lib/sssd.c +new file mode 100644 +index 00000000..80e49e55 +--- /dev/null ++++ b/lib/sssd.c +@@ -0,0 +1,75 @@ ++/* Author: Peter Vrabec */ ++ ++#include ++#ifdef USE_SSSD ++ ++#include ++#include ++#include ++#include "exitcodes.h" ++#include "defines.h" ++#include "prototypes.h" ++#include "sssd.h" ++ ++#define MSG_SSSD_FLUSH_CACHE_FAILED "%s: Failed to flush the sssd cache.\n" ++ ++int sssd_flush_cache (int dbflags) ++{ ++ int status, code, rv; ++ const char *cmd = "/usr/sbin/sss_cache"; ++ char *sss_cache_args = NULL; ++ const char *spawnedArgs[] = {"sss_cache", NULL, NULL}; ++ const char *spawnedEnv[] = {NULL}; ++ int i = 0; ++ ++ sss_cache_args = malloc(4); ++ if (sss_cache_args == NULL) { ++ return -1; ++ } ++ ++ sss_cache_args[i++] = '-'; ++ if (dbflags & SSSD_DB_PASSWD) { ++ sss_cache_args[i++] = 'U'; ++ } ++ if (dbflags & SSSD_DB_GROUP) { ++ sss_cache_args[i++] = 'G'; ++ } ++ sss_cache_args[i++] = '\0'; ++ if (i == 2) { ++ /* Neither passwd nor group, nothing to do */ ++ free(sss_cache_args); ++ return 0; ++ } ++ spawnedArgs[1] = sss_cache_args; ++ ++ rv = run_command (cmd, spawnedArgs, spawnedEnv, &status); ++ free(sss_cache_args); ++ if (rv != 0) { ++ /* run_command writes its own more detailed message. */ ++ (void) fprintf (stderr, _(MSG_SSSD_FLUSH_CACHE_FAILED), Prog); ++ return -1; ++ } ++ ++ code = WEXITSTATUS (status); ++ if (!WIFEXITED (status)) { ++ (void) fprintf (stderr, ++ _("%s: sss_cache did not terminate normally (signal %d)\n"), ++ Prog, WTERMSIG (status)); ++ return -1; ++ } else if (code == E_CMD_NOTFOUND) { ++ /* sss_cache is not installed, or it is installed but uses an ++ interpreter that is missing. Probably the former. */ ++ return 0; ++ } else if (code != 0) { ++ (void) fprintf (stderr, _("%s: sss_cache exited with status %d\n"), ++ Prog, code); ++ (void) fprintf (stderr, _(MSG_SSSD_FLUSH_CACHE_FAILED), Prog); ++ return -1; ++ } ++ ++ return 0; ++} ++#else /* USE_SSSD */ ++extern int errno; /* warning: ANSI C forbids an empty source file */ ++#endif /* USE_SSSD */ ++ +diff --git a/lib/sssd.h b/lib/sssd.h +new file mode 100644 +index 00000000..00ff2a8a +--- /dev/null ++++ b/lib/sssd.h +@@ -0,0 +1,17 @@ ++#ifndef _SSSD_H_ ++#define _SSSD_H_ ++ ++#define SSSD_DB_PASSWD 0x001 ++#define SSSD_DB_GROUP 0x002 ++ ++/* ++ * sssd_flush_cache - flush specified service buffer in sssd cache ++ */ ++#ifdef USE_SSSD ++extern int sssd_flush_cache (int dbflags); ++#else ++#define sssd_flush_cache(service) (0) ++#endif ++ ++#endif ++ +diff --git a/src/chfn.c b/src/chfn.c +index 18aa3de7..0725e1c7 100644 +--- a/src/chfn.c ++++ b/src/chfn.c +@@ -47,6 +47,7 @@ + #include "defines.h" + #include "getdef.h" + #include "nscd.h" ++#include "sssd.h" + #ifdef USE_PAM + #include "pam_defs.h" + #endif +@@ -746,6 +747,7 @@ int main (int argc, char **argv) + SYSLOG ((LOG_INFO, "changed user '%s' information", user)); + + nscd_flush_cache ("passwd"); ++ sssd_flush_cache (SSSD_DB_PASSWD); + + closelog (); + exit (E_SUCCESS); +diff --git a/src/chgpasswd.c b/src/chgpasswd.c +index 13203a46..e5f2eb7e 100644 +--- a/src/chgpasswd.c ++++ b/src/chgpasswd.c +@@ -46,6 +46,7 @@ + #endif /* ACCT_TOOLS_SETUID */ + #include "defines.h" + #include "nscd.h" ++#include "sssd.h" + #include "prototypes.h" + #include "groupio.h" + #ifdef SHADOWGRP +@@ -581,6 +582,7 @@ int main (int argc, char **argv) + close_files (); + + nscd_flush_cache ("group"); ++ sssd_flush_cache (SSSD_DB_GROUP); + + return (0); + } +diff --git a/src/chpasswd.c b/src/chpasswd.c +index 918b27ee..49e79cdb 100644 +--- a/src/chpasswd.c ++++ b/src/chpasswd.c +@@ -44,6 +44,7 @@ + #endif /* USE_PAM */ + #include "defines.h" + #include "nscd.h" ++#include "sssd.h" + #include "getdef.h" + #include "prototypes.h" + #include "pwio.h" +@@ -624,6 +625,7 @@ int main (int argc, char **argv) + } + + nscd_flush_cache ("passwd"); ++ sssd_flush_cache (SSSD_DB_PASSWD); + + return (0); + } +diff --git a/src/chsh.c b/src/chsh.c +index c89708b9..910e3dd4 100644 +--- a/src/chsh.c ++++ b/src/chsh.c +@@ -46,6 +46,7 @@ + #include "defines.h" + #include "getdef.h" + #include "nscd.h" ++#include "sssd.h" + #include "prototypes.h" + #include "pwauth.h" + #include "pwio.h" +@@ -557,6 +558,7 @@ int main (int argc, char **argv) + SYSLOG ((LOG_INFO, "changed user '%s' shell to '%s'", user, loginsh)); + + nscd_flush_cache ("passwd"); ++ sssd_flush_cache (SSSD_DB_PASSWD); + + closelog (); + exit (E_SUCCESS); +diff --git a/src/gpasswd.c b/src/gpasswd.c +index c4a492b1..4d75af96 100644 +--- a/src/gpasswd.c ++++ b/src/gpasswd.c +@@ -45,6 +45,7 @@ + #include "defines.h" + #include "groupio.h" + #include "nscd.h" ++#include "sssd.h" + #include "prototypes.h" + #ifdef SHADOWGRP + #include "sgroupio.h" +@@ -1201,6 +1202,7 @@ int main (int argc, char **argv) + close_files (); + + nscd_flush_cache ("group"); ++ sssd_flush_cache (SSSD_DB_GROUP); + + exit (E_SUCCESS); + } +diff --git a/src/groupadd.c b/src/groupadd.c +index b57006c5..2dd8eec9 100644 +--- a/src/groupadd.c ++++ b/src/groupadd.c +@@ -51,6 +51,7 @@ + #include "getdef.h" + #include "groupio.h" + #include "nscd.h" ++#include "sssd.h" + #include "prototypes.h" + #ifdef SHADOWGRP + #include "sgroupio.h" +@@ -625,6 +626,7 @@ int main (int argc, char **argv) + close_files (); + + nscd_flush_cache ("group"); ++ sssd_flush_cache (SSSD_DB_GROUP); + + return E_SUCCESS; + } +diff --git a/src/groupdel.c b/src/groupdel.c +index 70bed010..f941a84a 100644 +--- a/src/groupdel.c ++++ b/src/groupdel.c +@@ -49,6 +49,7 @@ + #include "defines.h" + #include "groupio.h" + #include "nscd.h" ++#include "sssd.h" + #include "prototypes.h" + #ifdef SHADOWGRP + #include "sgroupio.h" +@@ -492,6 +493,7 @@ int main (int argc, char **argv) + close_files (); + + nscd_flush_cache ("group"); ++ sssd_flush_cache (SSSD_DB_GROUP); + + return E_SUCCESS; + } +diff --git a/src/groupmod.c b/src/groupmod.c +index b293b98f..1dca5fc9 100644 +--- a/src/groupmod.c ++++ b/src/groupmod.c +@@ -51,6 +51,7 @@ + #include "groupio.h" + #include "pwio.h" + #include "nscd.h" ++#include "sssd.h" + #include "prototypes.h" + #ifdef SHADOWGRP + #include "sgroupio.h" +@@ -877,6 +878,7 @@ int main (int argc, char **argv) + close_files (); + + nscd_flush_cache ("group"); ++ sssd_flush_cache (SSSD_DB_GROUP); + + return E_SUCCESS; + } +diff --git a/src/grpck.c b/src/grpck.c +index ea5d3b39..6140b10d 100644 +--- a/src/grpck.c ++++ b/src/grpck.c +@@ -45,6 +45,7 @@ + #include "defines.h" + #include "groupio.h" + #include "nscd.h" ++#include "sssd.h" + #include "prototypes.h" + + #ifdef SHADOWGRP +@@ -870,6 +871,7 @@ int main (int argc, char **argv) + close_files (changed); + + nscd_flush_cache ("group"); ++ sssd_flush_cache (SSSD_DB_GROUP); + + /* + * Tell the user what we did and exit. +diff --git a/src/grpconv.c b/src/grpconv.c +index f95f4960..5e5eaaca 100644 +--- a/src/grpconv.c ++++ b/src/grpconv.c +@@ -48,6 +48,7 @@ + #include + #include + #include "nscd.h" ++#include "sssd.h" + #include "prototypes.h" + /*@-exitarg@*/ + #include "exitcodes.h" +@@ -273,6 +274,7 @@ int main (int argc, char **argv) + } + + nscd_flush_cache ("group"); ++ sssd_flush_cache (SSSD_DB_GROUP); + + return 0; + } +diff --git a/src/grpunconv.c b/src/grpunconv.c +index 253f06f5..e4105c26 100644 +--- a/src/grpunconv.c ++++ b/src/grpunconv.c +@@ -48,6 +48,7 @@ + #include + #include + #include "nscd.h" ++#include "sssd.h" + #include "prototypes.h" + /*@-exitarg@*/ + #include "exitcodes.h" +@@ -236,6 +237,7 @@ int main (int argc, char **argv) + } + + nscd_flush_cache ("group"); ++ sssd_flush_cache (SSSD_DB_GROUP); + + return 0; + } +diff --git a/src/newusers.c b/src/newusers.c +index 8e4bef97..7c3bb1c2 100644 +--- a/src/newusers.c ++++ b/src/newusers.c +@@ -62,6 +62,7 @@ + #include "getdef.h" + #include "groupio.h" + #include "nscd.h" ++#include "sssd.h" + #include "pwio.h" + #include "sgroupio.h" + #include "shadowio.h" +@@ -1233,6 +1234,7 @@ int main (int argc, char **argv) + + nscd_flush_cache ("passwd"); + nscd_flush_cache ("group"); ++ sssd_flush_cache (SSSD_DB_PASSWD | SSSD_DB_GROUP); + + #ifdef USE_PAM + unsigned int i; +diff --git a/src/passwd.c b/src/passwd.c +index 3af3e651..5bea2765 100644 +--- a/src/passwd.c ++++ b/src/passwd.c +@@ -51,6 +51,7 @@ + #include "defines.h" + #include "getdef.h" + #include "nscd.h" ++#include "sssd.h" + #include "prototypes.h" + #include "pwauth.h" + #include "pwio.h" +@@ -1150,6 +1151,7 @@ int main (int argc, char **argv) + + nscd_flush_cache ("passwd"); + nscd_flush_cache ("group"); ++ sssd_flush_cache (SSSD_DB_PASSWD | SSSD_DB_GROUP); + + SYSLOG ((LOG_INFO, "password for '%s' changed by '%s'", name, myname)); + closelog (); +diff --git a/src/pwck.c b/src/pwck.c +index 05df68ec..0ffb711e 100644 +--- a/src/pwck.c ++++ b/src/pwck.c +@@ -48,6 +48,7 @@ + #include "shadowio.h" + #include "getdef.h" + #include "nscd.h" ++#include "sssd.h" + #ifdef WITH_TCB + #include "tcbfuncs.h" + #endif /* WITH_TCB */ +@@ -877,6 +878,7 @@ int main (int argc, char **argv) + close_files (changed); + + nscd_flush_cache ("passwd"); ++ sssd_flush_cache (SSSD_DB_PASSWD); + + /* + * Tell the user what we did and exit. +diff --git a/src/pwconv.c b/src/pwconv.c +index d6ee31a8..9c69fa13 100644 +--- a/src/pwconv.c ++++ b/src/pwconv.c +@@ -72,6 +72,7 @@ + #include "pwio.h" + #include "shadowio.h" + #include "nscd.h" ++#include "sssd.h" + + /* + * exit status values +@@ -328,6 +329,7 @@ int main (int argc, char **argv) + } + + nscd_flush_cache ("passwd"); ++ sssd_flush_cache (SSSD_DB_PASSWD); + + return E_SUCCESS; + } +diff --git a/src/pwunconv.c b/src/pwunconv.c +index fabf0237..e11ea494 100644 +--- a/src/pwunconv.c ++++ b/src/pwunconv.c +@@ -42,6 +42,7 @@ + #include + #include "defines.h" + #include "nscd.h" ++#include "sssd.h" + #include "prototypes.h" + #include "pwio.h" + #include "shadowio.h" +@@ -250,6 +251,7 @@ int main (int argc, char **argv) + } + + nscd_flush_cache ("passwd"); ++ sssd_flush_cache (SSSD_DB_PASSWD); + + return 0; + } +diff --git a/src/useradd.c b/src/useradd.c +index ca90f076..b0c2224d 100644 +--- a/src/useradd.c ++++ b/src/useradd.c +@@ -60,6 +60,7 @@ + #include "getdef.h" + #include "groupio.h" + #include "nscd.h" ++#include "sssd.h" + #include "prototypes.h" + #include "pwauth.h" + #include "pwio.h" +@@ -2425,6 +2426,7 @@ int main (int argc, char **argv) + + nscd_flush_cache ("passwd"); + nscd_flush_cache ("group"); ++ sssd_flush_cache (SSSD_DB_PASSWD | SSSD_DB_GROUP); + + /* + * tallylog_reset needs to be able to lookup +diff --git a/src/userdel.c b/src/userdel.c +index c8de1d31..0715e4fe 100644 +--- a/src/userdel.c ++++ b/src/userdel.c +@@ -53,6 +53,7 @@ + #include "getdef.h" + #include "groupio.h" + #include "nscd.h" ++#include "sssd.h" + #include "prototypes.h" + #include "pwauth.h" + #include "pwio.h" +@@ -1328,6 +1329,7 @@ int main (int argc, char **argv) + + nscd_flush_cache ("passwd"); + nscd_flush_cache ("group"); ++ sssd_flush_cache (SSSD_DB_PASSWD | SSSD_DB_GROUP); + + return ((0 != errors) ? E_HOMEDIR : E_SUCCESS); + } +diff --git a/src/usermod.c b/src/usermod.c +index 7355ad31..fd9a98a6 100644 +--- a/src/usermod.c ++++ b/src/usermod.c +@@ -57,6 +57,7 @@ + #include "getdef.h" + #include "groupio.h" + #include "nscd.h" ++#include "sssd.h" + #include "prototypes.h" + #include "pwauth.h" + #include "pwio.h" +@@ -2255,6 +2256,7 @@ int main (int argc, char **argv) + + nscd_flush_cache ("passwd"); + nscd_flush_cache ("group"); ++ sssd_flush_cache (SSSD_DB_PASSWD | SSSD_DB_GROUP); + + #ifdef WITH_SELINUX + if (Zflg) { +diff --git a/src/vipw.c b/src/vipw.c +index 6d730f65..2cfac6b4 100644 +--- a/src/vipw.c ++++ b/src/vipw.c +@@ -42,6 +42,7 @@ + #include "defines.h" + #include "groupio.h" + #include "nscd.h" ++#include "sssd.h" + #include "prototypes.h" + #include "pwio.h" + #include "sgroupio.h" +@@ -556,6 +557,7 @@ int main (int argc, char **argv) + + nscd_flush_cache ("passwd"); + nscd_flush_cache ("group"); ++ sssd_flush_cache (SSSD_DB_PASSWD | SSSD_DB_GROUP); + + return E_SUCCESS; + } diff --git a/SOURCES/shadow-4.6-sssd-redirect-warning.patch b/SOURCES/shadow-4.6-sssd-redirect-warning.patch new file mode 100644 index 0000000..c452231 --- /dev/null +++ b/SOURCES/shadow-4.6-sssd-redirect-warning.patch @@ -0,0 +1,59 @@ +From 87257a49a1821d67870aa9760c71b6791583709c Mon Sep 17 00:00:00 2001 +From: ikerexxe +Date: Fri, 2 Oct 2020 16:09:42 +0200 +Subject: [PATCH] lib/sssd: redirect warning message to file + +Instead of printing warning in stderr print it to file. This way the +user is not spammed with unnecessary messages when updating packages. + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1749001 +--- + lib/sssd.c | 14 ++++++-------- + 1 file changed, 6 insertions(+), 8 deletions(-) + +diff --git a/lib/sssd.c b/lib/sssd.c +index 80e49e55..f864ce68 100644 +--- a/lib/sssd.c ++++ b/lib/sssd.c +@@ -11,7 +11,7 @@ + #include "prototypes.h" + #include "sssd.h" + +-#define MSG_SSSD_FLUSH_CACHE_FAILED "%s: Failed to flush the sssd cache.\n" ++#define MSG_SSSD_FLUSH_CACHE_FAILED "%s: Failed to flush the sssd cache." + + int sssd_flush_cache (int dbflags) + { +@@ -46,24 +46,22 @@ int sssd_flush_cache (int dbflags) + free(sss_cache_args); + if (rv != 0) { + /* run_command writes its own more detailed message. */ +- (void) fprintf (stderr, _(MSG_SSSD_FLUSH_CACHE_FAILED), Prog); ++ SYSLOG ((LOG_WARN, MSG_SSSD_FLUSH_CACHE_FAILED, Prog)); + return -1; + } + + code = WEXITSTATUS (status); + if (!WIFEXITED (status)) { +- (void) fprintf (stderr, +- _("%s: sss_cache did not terminate normally (signal %d)\n"), +- Prog, WTERMSIG (status)); ++ SYSLOG ((LOG_WARN, "%s: sss_cache did not terminate normally (signal %d)", ++ Prog, WTERMSIG (status))); + return -1; + } else if (code == E_CMD_NOTFOUND) { + /* sss_cache is not installed, or it is installed but uses an + interpreter that is missing. Probably the former. */ + return 0; + } else if (code != 0) { +- (void) fprintf (stderr, _("%s: sss_cache exited with status %d\n"), +- Prog, code); +- (void) fprintf (stderr, _(MSG_SSSD_FLUSH_CACHE_FAILED), Prog); ++ SYSLOG ((LOG_WARN, "%s: sss_cache exited with status %d", Prog, code)); ++ SYSLOG ((LOG_WARN, MSG_SSSD_FLUSH_CACHE_FAILED, Prog)); + return -1; + } + +-- +2.26.2 + diff --git a/SOURCES/shadow-4.6-sysugid-min-limit.patch b/SOURCES/shadow-4.6-sysugid-min-limit.patch new file mode 100644 index 0000000..4cea6ef --- /dev/null +++ b/SOURCES/shadow-4.6-sysugid-min-limit.patch @@ -0,0 +1,34 @@ +diff -up shadow-4.6/libmisc/find_new_gid.c.min-limit shadow-4.6/libmisc/find_new_gid.c +--- shadow-4.6/libmisc/find_new_gid.c.min-limit 2018-04-29 18:42:37.000000001 +0200 ++++ shadow-4.6/libmisc/find_new_gid.c 2018-11-06 10:51:20.554963292 +0100 +@@ -82,6 +82,13 @@ static int get_ranges (bool sys_group, g + (unsigned long) *max_id); + return EINVAL; + } ++ /* ++ * Zero is reserved for root and the allocation algorithm does not ++ * work right with it. ++ */ ++ if (*min_id == 0) { ++ *min_id = (gid_t) 1; ++ } + } else { + /* Non-system groups */ + +diff -up shadow-4.6/libmisc/find_new_uid.c.min-limit shadow-4.6/libmisc/find_new_uid.c +--- shadow-4.6/libmisc/find_new_uid.c.min-limit 2018-04-29 18:42:37.000000001 +0200 ++++ shadow-4.6/libmisc/find_new_uid.c 2018-11-06 10:51:39.341399569 +0100 +@@ -82,6 +82,13 @@ static int get_ranges (bool sys_user, ui + (unsigned long) *max_id); + return EINVAL; + } ++ /* ++ * Zero is reserved for root and the allocation algorithm does not ++ * work right with it. ++ */ ++ if (*min_id == 0) { ++ *min_id = (uid_t) 1; ++ } + } else { + /* Non-system users */ + diff --git a/SOURCES/shadow-4.6-use-itstool.patch b/SOURCES/shadow-4.6-use-itstool.patch new file mode 100644 index 0000000..760b5b3 --- /dev/null +++ b/SOURCES/shadow-4.6-use-itstool.patch @@ -0,0 +1,31 @@ +diff -up shadow-4.6/man/generate_translations.mak.use-itstool shadow-4.6/man/generate_translations.mak +--- shadow-4.6/man/generate_translations.mak.use-itstool 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/man/generate_translations.mak 2018-07-31 16:42:21.623990969 +0200 +@@ -5,8 +5,19 @@ config.xml: ../config.xml.in + $(MAKE) -C .. config.xml + cp ../config.xml $@ + +-%.xml: ../%.xml ../po/$(LANG).po +- xml2po --expand-all-entities -l $(LANG) -p ../po/$(LANG).po -o $@ ../$@ ++messages.mo: ../po/$(LANG).po ++ msgfmt ../po/$(LANG).po -o messages.mo ++ ++login.defs.d: ++ ln -sf ../login.defs.d login.defs.d ++ ++%.xml: ../%.xml messages.mo login.defs.d ++ if grep -q SHADOW-CONFIG-HERE $< ; then \ ++ sed -e 's/^/%config;/' $< > $@; \ ++ else \ ++ sed -e 's/^\(/\1 [%config;]>/' $< > $@; \ ++ fi ++ itstool -d -l $(LANG) -m messages.mo -o . $@ + sed -i 's:\(^:\1 lang="$(LANG)">:' $@ + + include ../generate_mans.mak +@@ -16,4 +27,4 @@ $(man_MANS): + @echo you need to run configure with --enable-man to generate man pages + endif + +-CLEANFILES = .xml2po.mo $(EXTRA_DIST) $(addsuffix .xml,$(EXTRA_DIST)) config.xml ++CLEANFILES = messages.mo login.defs.d $(EXTRA_DIST) $(addsuffix .xml,$(EXTRA_DIST)) config.xml diff --git a/SOURCES/shadow-4.6-use-lckpwdf.patch b/SOURCES/shadow-4.6-use-lckpwdf.patch new file mode 100644 index 0000000..363579a --- /dev/null +++ b/SOURCES/shadow-4.6-use-lckpwdf.patch @@ -0,0 +1,190 @@ +commit 408b8a548243aebaa6d773beeae8ddf4bb6100f0 +Author: Tomas Mraz +Date: Thu May 2 14:33:06 2019 +0200 + + Use the lckpwdf() again if prefix is not set + + The implementation of prefix option dropped the use of lckpwdf(). + However that is incorrect as other tools manipulating the shadow passwords + such as PAM use lckpwdf() and do not know anything about the + shadow's own locking mechanism. + + This reverts the implementation to use lckpwdf() if prefix option + is not used. + +diff --git a/lib/commonio.c b/lib/commonio.c +index 26e518f2..94dda779 100644 +--- a/lib/commonio.c ++++ b/lib/commonio.c +@@ -364,6 +364,7 @@ static void free_linked_list (struct commonio_db *db) + int commonio_setname (struct commonio_db *db, const char *name) + { + snprintf (db->filename, sizeof (db->filename), "%s", name); ++ db->setname = true; + return 1; + } + +@@ -414,37 +415,39 @@ cleanup_ENOMEM: + + int commonio_lock (struct commonio_db *db) + { +-/*#ifdef HAVE_LCKPWDF*/ /* not compatible with prefix option*/ +-#if 0 +- /* +- * only if the system libc has a real lckpwdf() - the one from +- * lockpw.c calls us and would cause infinite recursion! +- */ ++ int i; + ++#ifdef HAVE_LCKPWDF + /* +- * Call lckpwdf() on the first lock. +- * If it succeeds, call *_lock() only once +- * (no retries, it should always succeed). ++ * Only if the system libc has a real lckpwdf() - the one from ++ * lockpw.c calls us and would cause infinite recursion! ++ * It is also not used with the prefix option. + */ +- if (0 == lock_count) { +- if (lckpwdf () == -1) { +- if (geteuid () != 0) { +- (void) fprintf (stderr, +- "%s: Permission denied.\n", +- Prog); ++ if (!db->setname) { ++ /* ++ * Call lckpwdf() on the first lock. ++ * If it succeeds, call *_lock() only once ++ * (no retries, it should always succeed). ++ */ ++ if (0 == lock_count) { ++ if (lckpwdf () == -1) { ++ if (geteuid () != 0) { ++ (void) fprintf (stderr, ++ "%s: Permission denied.\n", ++ Prog); ++ } ++ return 0; /* failure */ + } +- return 0; /* failure */ + } +- } + +- if (commonio_lock_nowait (db, true) != 0) { +- return 1; /* success */ +- } ++ if (commonio_lock_nowait (db, true) != 0) { ++ return 1; /* success */ ++ } + +- ulckpwdf (); +- return 0; /* failure */ +-#else /* !HAVE_LCKPWDF */ +- int i; ++ ulckpwdf (); ++ return 0; /* failure */ ++ } ++#endif /* !HAVE_LCKPWDF */ + + /* + * lckpwdf() not used - do it the old way. +@@ -471,7 +474,6 @@ int commonio_lock (struct commonio_db *db) + } + } + return 0; /* failure */ +-#endif /* !HAVE_LCKPWDF */ + } + + static void dec_lock_count (void) +diff --git a/lib/commonio.h b/lib/commonio.h +index 40e5708f..64e83073 100644 +--- a/lib/commonio.h ++++ b/lib/commonio.h +@@ -143,6 +143,7 @@ struct commonio_db { + bool isopen:1; + bool locked:1; + bool readonly:1; ++ bool setname:1; + }; + + extern int commonio_setname (struct commonio_db *, const char *); +diff --git a/lib/groupio.c b/lib/groupio.c +index ae2302b5..bffb06e0 100644 +--- a/lib/groupio.c ++++ b/lib/groupio.c +@@ -139,7 +139,8 @@ static /*@owned@*/struct commonio_db group_db = { + false, /* changed */ + false, /* isopen */ + false, /* locked */ +- false /* readonly */ ++ false, /* readonly */ ++ false /* setname */ + }; + + int gr_setdbname (const char *filename) +diff --git a/lib/pwio.c b/lib/pwio.c +index 7ee85377..127719cb 100644 +--- a/lib/pwio.c ++++ b/lib/pwio.c +@@ -114,7 +114,8 @@ static struct commonio_db passwd_db = { + false, /* changed */ + false, /* isopen */ + false, /* locked */ +- false /* readonly */ ++ false, /* readonly */ ++ false /* setname */ + }; + + int pw_setdbname (const char *filename) +diff --git a/lib/sgroupio.c b/lib/sgroupio.c +index 5423626a..ffbdb263 100644 +--- a/lib/sgroupio.c ++++ b/lib/sgroupio.c +@@ -238,7 +238,8 @@ static struct commonio_db gshadow_db = { + false, /* changed */ + false, /* isopen */ + false, /* locked */ +- false /* readonly */ ++ false, /* readonly */ ++ false /* setname */ + }; + + int sgr_setdbname (const char *filename) +diff --git a/lib/shadowio.c b/lib/shadowio.c +index 5fa3d312..676b1f1a 100644 +--- a/lib/shadowio.c ++++ b/lib/shadowio.c +@@ -114,7 +114,8 @@ static struct commonio_db shadow_db = { + false, /* changed */ + false, /* isopen */ + false, /* locked */ +- false /* readonly */ ++ false, /* readonly */ ++ false /* setname */ + }; + + int spw_setdbname (const char *filename) +diff --git a/lib/subordinateio.c b/lib/subordinateio.c +index a662e67e..dd779c59 100644 +--- a/lib/subordinateio.c ++++ b/lib/subordinateio.c +@@ -550,7 +550,8 @@ static struct commonio_db subordinate_uid_db = { + false, /* changed */ + false, /* isopen */ + false, /* locked */ +- false /* readonly */ ++ false, /* readonly */ ++ false /* setname */ + }; + + int sub_uid_setdbname (const char *filename) +@@ -631,7 +632,8 @@ static struct commonio_db subordinate_gid_db = { + false, /* changed */ + false, /* isopen */ + false, /* locked */ +- false /* readonly */ ++ false, /* readonly */ ++ false /* setname */ + }; + + int sub_gid_setdbname (const char *filename) diff --git a/SOURCES/shadow-4.6-useradd-check-if-subid-range-exists.patch b/SOURCES/shadow-4.6-useradd-check-if-subid-range-exists.patch new file mode 100644 index 0000000..de44ace --- /dev/null +++ b/SOURCES/shadow-4.6-useradd-check-if-subid-range-exists.patch @@ -0,0 +1,20 @@ +diff -up shadow-4.6/src/useradd.c.useradd-check-if-subid-range-exists shadow-4.6/src/useradd.c +--- shadow-4.6/src/useradd.c.useradd-check-if-subid-range-exists 2023-05-17 10:39:41.457826153 +0200 ++++ shadow-4.6/src/useradd.c 2023-05-17 10:41:30.937036772 +0200 +@@ -2019,14 +2019,14 @@ static void usr_update (void) + fail_exit (E_PW_UPDATE); + } + #ifdef ENABLE_SUBIDS +- if (is_sub_uid && ++ if (is_sub_uid && !local_sub_uid_assigned(user_name) && + (sub_uid_add(user_name, sub_uid_start, sub_uid_count) == 0)) { + fprintf (stderr, + _("%s: failed to prepare the new %s entry\n"), + Prog, sub_uid_dbname ()); + fail_exit (E_SUB_UID_UPDATE); + } +- if (is_sub_gid && ++ if (is_sub_gid && !local_sub_gid_assigned(user_name) && + (sub_gid_add(user_name, sub_gid_start, sub_gid_count) == 0)) { + fprintf (stderr, + _("%s: failed to prepare the new %s entry\n"), diff --git a/SOURCES/shadow-4.6-useradd_SUB_UID_COUNT-0.patch b/SOURCES/shadow-4.6-useradd_SUB_UID_COUNT-0.patch new file mode 100644 index 0000000..f393368 --- /dev/null +++ b/SOURCES/shadow-4.6-useradd_SUB_UID_COUNT-0.patch @@ -0,0 +1,44 @@ +From 663824ef4ca927aa2b4319b69e0bfa68282ec719 Mon Sep 17 00:00:00 2001 +From: Serge Hallyn +Date: Sat, 22 May 2021 11:42:02 -0500 +Subject: [PATCH] Fix useradd with SUB_UID_COUNT=0 + +Closes #298 + +Fix useradd when SUB_UID_COUNT=0 in login.defs. + +Signed-off-by: Serge Hallyn +--- + src/useradd.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/src/useradd.c b/src/useradd.c +index 06accb2f..9862ae55 100644 +--- a/src/useradd.c ++++ b/src/useradd.c +@@ -2386,6 +2386,8 @@ int main (int argc, char **argv) + #ifdef ENABLE_SUBIDS + uid_t uid_min; + uid_t uid_max; ++ unsigned long subuid_count; ++ unsigned long subgid_count; + #endif + + /* +@@ -2427,9 +2429,11 @@ int main (int argc, char **argv) + #ifdef ENABLE_SUBIDS + uid_min = (uid_t) getdef_ulong ("UID_MIN", 1000UL); + uid_max = (uid_t) getdef_ulong ("UID_MAX", 60000UL); +- is_sub_uid = sub_uid_file_present () && !rflg && ++ subuid_count = getdef_ulong ("SUB_UID_COUNT", 65536); ++ subgid_count = getdef_ulong ("SUB_GID_COUNT", 65536); ++ is_sub_uid = subuid_count > 0 && sub_uid_file_present () && !rflg && + (!user_id || (user_id <= uid_max && user_id >= uid_min)); +- is_sub_gid = sub_gid_file_present () && !rflg && ++ is_sub_gid = subgid_count > 0 && sub_gid_file_present () && !rflg && + (!user_id || (user_id <= uid_max && user_id >= uid_min)); + #endif /* ENABLE_SUBIDS */ + +-- +2.30.2 + diff --git a/SOURCES/shadow-4.6-useradd_dont_try_to_create_0_subuids.patch b/SOURCES/shadow-4.6-useradd_dont_try_to_create_0_subuids.patch new file mode 100644 index 0000000..a53d724 --- /dev/null +++ b/SOURCES/shadow-4.6-useradd_dont_try_to_create_0_subuids.patch @@ -0,0 +1,21 @@ +diff -up shadow-4.6/src/useradd.c.useradd_dont_try_to_create_0_subuids shadow-4.6/src/useradd.c +--- shadow-4.6/src/useradd.c.useradd_dont_try_to_create_0_subuids 2021-11-03 11:55:00.189562187 +0100 ++++ shadow-4.6/src/useradd.c 2021-11-03 11:57:34.128658978 +0100 +@@ -2350,7 +2350,7 @@ int main (int argc, char **argv) + } + + #ifdef ENABLE_SUBIDS +- if (is_sub_uid) { ++ if (is_sub_uid && subuid_count != 0) { + if (find_new_sub_uids(user_name, &sub_uid_start, &sub_uid_count) < 0) { + fprintf (stderr, + _("%s: can't create subordinate user IDs\n"), +@@ -2358,7 +2358,7 @@ int main (int argc, char **argv) + fail_exit(E_SUB_UID_UPDATE); + } + } +- if (is_sub_gid) { ++ if (is_sub_gid && subgid_count != 0) { + if (find_new_sub_gids(user_name, &sub_gid_start, &sub_gid_count) < 0) { + fprintf (stderr, + _("%s: can't create subordinate group IDs\n"), diff --git a/SOURCES/shadow-4.6-usermod-allow-all-group-types.patch b/SOURCES/shadow-4.6-usermod-allow-all-group-types.patch new file mode 100644 index 0000000..fada15e --- /dev/null +++ b/SOURCES/shadow-4.6-usermod-allow-all-group-types.patch @@ -0,0 +1,322 @@ +From e481437ab9ebe9a8bf8fbaabe986d42b2f765991 Mon Sep 17 00:00:00 2001 +From: Iker Pedrosa +Date: Tue, 3 Aug 2021 08:57:20 +0200 +Subject: [PATCH] usermod: allow all group types with -G option + +The only way of removing a group from the supplementary list is to use +-G option, and list all groups that the user is a member of except for +the one that wants to be removed. The problem lies when there's a user +that contains both local and remote groups, and the group to be removed +is a local one. As we need to include the remote group with -G option +the command will fail. + +This reverts commit 140510de9de4771feb3af1d859c09604043a4c9b. This way, +it would be possible to remove the remote groups from the supplementary +list. + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1967641 +Resolves: https://github.com/shadow-maint/shadow/issues/338 + +Signed-off-by: Iker Pedrosa +--- + src/usermod.c | 220 ++++++++++++++++++-------------------------------- + 1 file changed, 77 insertions(+), 143 deletions(-) + +diff --git a/src/usermod.c b/src/usermod.c +index 03bb9b9d..a0c03afa 100644 +--- a/src/usermod.c ++++ b/src/usermod.c +@@ -187,7 +187,6 @@ static bool sub_gid_locked = false; + static void date_to_str (/*@unique@*//*@out@*/char *buf, size_t maxsize, + long int date); + static int get_groups (char *); +-static struct group * get_local_group (char * grp_name); + static /*@noreturn@*/void usage (int status); + static void new_pwent (struct passwd *); + static void new_spent (struct spwd *); +@@ -201,9 +200,7 @@ static void grp_update (void); + + static void process_flags (int, char **); + static void close_files (void); +-static void close_group_files (void); + static void open_files (void); +-static void open_group_files (void); + static void usr_update (void); + static void move_home (void); + static void update_lastlog (void); +@@ -260,11 +257,6 @@ static int get_groups (char *list) + return 0; + } + +- /* +- * Open the group files +- */ +- open_group_files (); +- + /* + * So long as there is some data to be converted, strip off each + * name and look it up. A mix of numerical and string values for +@@ -284,7 +276,7 @@ static int get_groups (char *list) + * Names starting with digits are treated as numerical GID + * values, otherwise the string is looked up as is. + */ +- grp = get_local_group (list); ++ grp = prefix_getgr_nam_gid (list); + + /* + * There must be a match, either by GID value or by +@@ -334,8 +326,6 @@ static int get_groups (char *list) + gr_free ((struct group *)grp); + } while (NULL != list); + +- close_group_files (); +- + user_groups[ngroups] = (char *) 0; + + /* +@@ -348,44 +338,6 @@ static int get_groups (char *list) + return 0; + } + +-/* +- * get_local_group - checks if a given group name exists locally +- * +- * get_local_group() checks if a given group name exists locally. +- * If the name exists the group information is returned, otherwise NULL is +- * returned. +- */ +-static struct group * get_local_group(char * grp_name) +-{ +- const struct group *grp; +- struct group *result_grp = NULL; +- long long int gid; +- char *endptr; +- +- gid = strtoll (grp_name, &endptr, 10); +- if ( ('\0' != *grp_name) +- && ('\0' == *endptr) +- && (ERANGE != errno) +- && (gid == (gid_t)gid)) { +- grp = gr_locate_gid ((gid_t) gid); +- } +- else { +- grp = gr_locate(grp_name); +- } +- +- if (grp != NULL) { +- result_grp = __gr_dup (grp); +- if (NULL == result_grp) { +- fprintf (stderr, +- _("%s: Out of memory. Cannot find group '%s'.\n"), +- Prog, grp_name); +- fail_exit (E_GRP_UPDATE); +- } +- } +- +- return result_grp; +-} +- + #ifdef ENABLE_SUBIDS + struct ulong_range + { +@@ -1523,7 +1475,50 @@ static void close_files (void) + } + + if (Gflg || lflg) { +- close_group_files (); ++ if (gr_close () == 0) { ++ fprintf (stderr, ++ _("%s: failure while writing changes to %s\n"), ++ Prog, gr_dbname ()); ++ SYSLOG ((LOG_ERR, ++ "failure while writing changes to %s", ++ gr_dbname ())); ++ fail_exit (E_GRP_UPDATE); ++ } ++#ifdef SHADOWGRP ++ if (is_shadow_grp) { ++ if (sgr_close () == 0) { ++ fprintf (stderr, ++ _("%s: failure while writing changes to %s\n"), ++ Prog, sgr_dbname ()); ++ SYSLOG ((LOG_ERR, ++ "failure while writing changes to %s", ++ sgr_dbname ())); ++ fail_exit (E_GRP_UPDATE); ++ } ++ } ++#endif ++#ifdef SHADOWGRP ++ if (is_shadow_grp) { ++ if (sgr_unlock () == 0) { ++ fprintf (stderr, ++ _("%s: failed to unlock %s\n"), ++ Prog, sgr_dbname ()); ++ SYSLOG ((LOG_ERR, ++ "failed to unlock %s", ++ sgr_dbname ())); ++ /* continue */ ++ } ++ } ++#endif ++ if (gr_unlock () == 0) { ++ fprintf (stderr, ++ _("%s: failed to unlock %s\n"), ++ Prog, gr_dbname ()); ++ SYSLOG ((LOG_ERR, ++ "failed to unlock %s", ++ gr_dbname ())); ++ /* continue */ ++ } + } + + if (is_shadow_pwd) { +@@ -1592,60 +1587,6 @@ static void close_files (void) + #endif + } + +-/* +- * close_group_files - close all of the files that were opened +- * +- * close_group_files() closes all of the files that were opened related +- * with groups. This causes any modified entries to be written out. +- */ +-static void close_group_files (void) +-{ +- if (gr_close () == 0) { +- fprintf (stderr, +- _("%s: failure while writing changes to %s\n"), +- Prog, gr_dbname ()); +- SYSLOG ((LOG_ERR, +- "failure while writing changes to %s", +- gr_dbname ())); +- fail_exit (E_GRP_UPDATE); +- } +-#ifdef SHADOWGRP +- if (is_shadow_grp) { +- if (sgr_close () == 0) { +- fprintf (stderr, +- _("%s: failure while writing changes to %s\n"), +- Prog, sgr_dbname ()); +- SYSLOG ((LOG_ERR, +- "failure while writing changes to %s", +- sgr_dbname ())); +- fail_exit (E_GRP_UPDATE); +- } +- } +-#endif +-#ifdef SHADOWGRP +- if (is_shadow_grp) { +- if (sgr_unlock () == 0) { +- fprintf (stderr, +- _("%s: failed to unlock %s\n"), +- Prog, sgr_dbname ()); +- SYSLOG ((LOG_ERR, +- "failed to unlock %s", +- sgr_dbname ())); +- /* continue */ +- } +- } +-#endif +- if (gr_unlock () == 0) { +- fprintf (stderr, +- _("%s: failed to unlock %s\n"), +- Prog, gr_dbname ()); +- SYSLOG ((LOG_ERR, +- "failed to unlock %s", +- gr_dbname ())); +- /* continue */ +- } +-} +- + /* + * open_files - lock and open the password files + * +@@ -1681,7 +1622,38 @@ static void open_files (void) + } + + if (Gflg || lflg) { +- open_group_files (); ++ /* ++ * Lock and open the group file. This will load all of the ++ * group entries. ++ */ ++ if (gr_lock () == 0) { ++ fprintf (stderr, ++ _("%s: cannot lock %s; try again later.\n"), ++ Prog, gr_dbname ()); ++ fail_exit (E_GRP_UPDATE); ++ } ++ gr_locked = true; ++ if (gr_open (O_CREAT | O_RDWR) == 0) { ++ fprintf (stderr, ++ _("%s: cannot open %s\n"), ++ Prog, gr_dbname ()); ++ fail_exit (E_GRP_UPDATE); ++ } ++#ifdef SHADOWGRP ++ if (is_shadow_grp && (sgr_lock () == 0)) { ++ fprintf (stderr, ++ _("%s: cannot lock %s; try again later.\n"), ++ Prog, sgr_dbname ()); ++ fail_exit (E_GRP_UPDATE); ++ } ++ sgr_locked = true; ++ if (is_shadow_grp && (sgr_open (O_CREAT | O_RDWR) == 0)) { ++ fprintf (stderr, ++ _("%s: cannot open %s\n"), ++ Prog, sgr_dbname ()); ++ fail_exit (E_GRP_UPDATE); ++ } ++#endif + } + #ifdef ENABLE_SUBIDS + if (vflg || Vflg) { +@@ -1717,44 +1689,6 @@ static void open_files (void) + #endif /* ENABLE_SUBIDS */ + } + +-/* +- * open_group_files - lock and open the group files +- * +- * open_group_files() loads all of the group entries. +- */ +-static void open_group_files (void) +-{ +- if (gr_lock () == 0) { +- fprintf (stderr, +- _("%s: cannot lock %s; try again later.\n"), +- Prog, gr_dbname ()); +- fail_exit (E_GRP_UPDATE); +- } +- gr_locked = true; +- if (gr_open (O_CREAT | O_RDWR) == 0) { +- fprintf (stderr, +- _("%s: cannot open %s\n"), +- Prog, gr_dbname ()); +- fail_exit (E_GRP_UPDATE); +- } +- +-#ifdef SHADOWGRP +- if (is_shadow_grp && (sgr_lock () == 0)) { +- fprintf (stderr, +- _("%s: cannot lock %s; try again later.\n"), +- Prog, sgr_dbname ()); +- fail_exit (E_GRP_UPDATE); +- } +- sgr_locked = true; +- if (is_shadow_grp && (sgr_open (O_CREAT | O_RDWR) == 0)) { +- fprintf (stderr, +- _("%s: cannot open %s\n"), +- Prog, sgr_dbname ()); +- fail_exit (E_GRP_UPDATE); +- } +-#endif +-} +- + /* + * usr_update - create the user entries + * +-- +2.31.1 + diff --git a/SOURCES/shadow-4.6-usermod-crash.patch b/SOURCES/shadow-4.6-usermod-crash.patch new file mode 100644 index 0000000..d2861b3 --- /dev/null +++ b/SOURCES/shadow-4.6-usermod-crash.patch @@ -0,0 +1,42 @@ +diff -up shadow-4.6/libmisc/prefix_flag.c.usermod-crash shadow-4.6/libmisc/prefix_flag.c +--- shadow-4.6/libmisc/prefix_flag.c.usermod-crash 2018-04-29 18:42:37.000000000 +0200 ++++ shadow-4.6/libmisc/prefix_flag.c 2018-05-28 15:14:10.642302440 +0200 +@@ -319,6 +319,7 @@ extern struct group *prefix_getgr_nam_gi + { + long long int gid; + char *endptr; ++ struct group *g; + + if (NULL == grname) { + return NULL; +@@ -333,7 +334,8 @@ extern struct group *prefix_getgr_nam_gi + && (gid == (gid_t)gid)) { + return prefix_getgrgid ((gid_t) gid); + } +- return prefix_getgrnam (grname); ++ g = prefix_getgrnam (grname); ++ return g ? __gr_dup(g) : NULL; + } + else + return getgr_nam_gid(grname); +diff -up shadow-4.6/src/usermod.c.usermod-crash shadow-4.6/src/usermod.c +--- shadow-4.6/src/usermod.c.usermod-crash 2018-05-28 15:12:37.920332763 +0200 ++++ shadow-4.6/src/usermod.c 2018-05-28 15:15:50.337422470 +0200 +@@ -1276,11 +1276,13 @@ static void process_flags (int argc, cha + prefix_user_home = xmalloc(len); + wlen = snprintf(prefix_user_home, len, "%s/%s", prefix, user_home); + assert (wlen == (int) len -1); ++ if (user_newhome) { ++ len = strlen(prefix) + strlen(user_newhome) + 2; ++ prefix_user_newhome = xmalloc(len); ++ wlen = snprintf(prefix_user_newhome, len, "%s/%s", prefix, user_newhome); ++ assert (wlen == (int) len -1); ++ } + +- len = strlen(prefix) + strlen(user_newhome) + 2; +- prefix_user_newhome = xmalloc(len); +- wlen = snprintf(prefix_user_newhome, len, "%s/%s", prefix, user_newhome); +- assert (wlen == (int) len -1); + } + else { + prefix_user_home = user_home; diff --git a/SOURCES/shadow-4.6.tar.xz.asc b/SOURCES/shadow-4.6.tar.xz.asc new file mode 100644 index 0000000..e36c97f --- /dev/null +++ b/SOURCES/shadow-4.6.tar.xz.asc @@ -0,0 +1,11 @@ +-----BEGIN PGP SIGNATURE----- + +iQEzBAABCgAdFiEE8dCNt3gYW/eEAC3/6f7qBqheP50FAlrncOkACgkQ6f7qBqhe +P52UGAf/eOnoIYIZ52y72iMxeNfQMTMjYTZd1YrtjlK0RQKquK7FrCOg91MvOF2B +hLVKu2OU7mzuPTMSAraAxjXLkrM0E3vFjMtu1fHBGlGTMspAfik/9Gu9qoevAKXy +BRqgN5m5HMfoGPeEjzILzaGq8bnPKIOfJ0iAYVkjjIa73Vn20uTmNgNZIRqHqwfw +5GUFHn6cjQXFcQ3ngywgwQD7/h/65w8dBbGysF551sAqzPJRbneQL9Wtklcqi1ub +55NyF0ifT67RqMh+EyxhuhXP1Hi57PTEAeqaFMFxnPlQPb+8pQ8nszWBmI+vUN8D +FmhwCtSTnmKlj0jeAqevmkijJhGPQQ== +=fk/F +-----END PGP SIGNATURE----- diff --git a/SOURCES/shadow-4.9-subordinateio-compare-owner-ID.patch b/SOURCES/shadow-4.9-subordinateio-compare-owner-ID.patch new file mode 100644 index 0000000..19ab7ec --- /dev/null +++ b/SOURCES/shadow-4.9-subordinateio-compare-owner-ID.patch @@ -0,0 +1,108 @@ +From 3ec32f9975f262073f8fbdecd2bfaee4a1d3db48 Mon Sep 17 00:00:00 2001 +From: Iker Pedrosa +Date: Wed, 13 Jul 2022 09:55:14 +0200 +Subject: [PATCH] subordinateio: also compare the owner ID + +IDs already populate /etc/subuid and /etc/subgid files so it's necessary +not only to check for the owner name but also for the owner ID of a +given range. + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2093311 + +Signed-off-by: Iker Pedrosa +--- + lib/subordinateio.c | 50 +++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 50 insertions(+) + +diff --git a/lib/subordinateio.c b/lib/subordinateio.c +index 9ca70b8b..6bc45283 100644 +--- a/lib/subordinateio.c ++++ b/lib/subordinateio.c +@@ -17,6 +17,8 @@ + #include + #include + ++#define ID_SIZE 31 ++ + /* + * subordinate_dup: create a duplicate range + * +@@ -745,6 +747,40 @@ gid_t sub_gid_find_free_range(gid_t min, gid_t max, unsigned long count) + return start == ULONG_MAX ? (gid_t) -1 : start; + } + ++static bool get_owner_id(const char *owner, enum subid_type id_type, char *id) ++{ ++ struct passwd *pw; ++ struct group *gr; ++ int ret = 0; ++ ++ switch (id_type) { ++ case ID_TYPE_UID: ++ pw = getpwnam(owner); ++ if (pw == NULL) { ++ return false; ++ } ++ ret = snprintf(id, ID_SIZE, "%u", pw->pw_uid); ++ if (ret < 0 || ret >= ID_SIZE) { ++ return false; ++ } ++ break; ++ case ID_TYPE_GID: ++ gr = getgrnam(owner); ++ if (gr == NULL) { ++ return false; ++ } ++ ret = snprintf(id, ID_SIZE, "%u", gr->gr_gid); ++ if (ret < 0 || ret >= ID_SIZE) { ++ return false; ++ } ++ break; ++ default: ++ return false; ++ } ++ ++ return true; ++} ++ + /* + * int list_owner_ranges(const char *owner, enum subid_type id_type, struct subordinate_range ***ranges) + * +@@ -770,6 +806,8 @@ int list_owner_ranges(const char *owner, enum subid_type id_type, struct subid_r + enum subid_status status; + int count = 0; + struct subid_nss_ops *h; ++ char id[ID_SIZE]; ++ bool have_owner_id; + + *in_ranges = NULL; + +@@ -798,6 +836,8 @@ int list_owner_ranges(const char *owner, enum subid_type id_type, struct subid_r + return -1; + } + ++ have_owner_id = get_owner_id(owner, id_type, id); ++ + commonio_rewind(db); + while ((range = commonio_next(db)) != NULL) { + if (0 == strcmp(range->owner, owner)) { +@@ -808,6 +848,16 @@ int list_owner_ranges(const char *owner, enum subid_type id_type, struct subid_r + goto out; + } + } ++ ++ // Let's also compare with the ID ++ if (have_owner_id == true && 0 == strcmp(range->owner, id)) { ++ if (!append_range(&ranges, range, count++)) { ++ free(ranges); ++ ranges = NULL; ++ count = -1; ++ goto out; ++ } ++ } + } + + out: +-- +2.36.1 + diff --git a/SOURCES/shadow-bsd.txt b/SOURCES/shadow-bsd.txt new file mode 100644 index 0000000..a2c1609 --- /dev/null +++ b/SOURCES/shadow-bsd.txt @@ -0,0 +1,32 @@ +/* + * Copyright (c) 1990 - 1994, Julianne Frances Haugh + * Copyright (c) 1996 - 2000, Marek Michałkiewicz + * Copyright (c) 2000 - 2006, Tomasz Kłoczko + * Copyright (c) 2007 - 2011, Nicolas François + * All rights reserved. + * + * 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, this list of conditions and the following disclaimer. + * 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 copyright holders or contributors may not be used to + * endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``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 COPYRIGHT + * HOLDERS OR CONTRIBUTORS 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. + */ + diff --git a/SOURCES/shadow-utils.login.defs b/SOURCES/shadow-utils.login.defs new file mode 100644 index 0000000..c50e46e --- /dev/null +++ b/SOURCES/shadow-utils.login.defs @@ -0,0 +1,98 @@ +# +# Please note that the parameters in this configuration file control the +# behavior of the tools from the shadow-utils component. None of these +# tools uses the PAM mechanism, and the utilities that use PAM (such as the +# passwd command) should therefore be configured elsewhere. Refer to +# /etc/pam.d/system-auth for more information. +# + +# *REQUIRED* +# Directory where mailboxes reside, _or_ name of file, relative to the +# home directory. If you _do_ define both, MAIL_DIR takes precedence. +# QMAIL_DIR is for Qmail +# +#QMAIL_DIR Maildir +MAIL_DIR /var/spool/mail +#MAIL_FILE .mail + +# Default initial "umask" value used by login(1) on non-PAM enabled systems. +# Default "umask" value for pam_umask(8) on PAM enabled systems. +# UMASK is also used by useradd(8) and newusers(8) to set the mode for new +# home directories if HOME_MODE is not set. +# 022 is the default value, but 027, or even 077, could be considered +# for increased privacy. There is no One True Answer here: each sysadmin +# must make up their mind. +UMASK 022 + +# HOME_MODE is used by useradd(8) and newusers(8) to set the mode for new +# home directories. +# If HOME_MODE is not set, the value of UMASK is used to create the mode. +HOME_MODE 0700 + +# Password aging controls: +# +# PASS_MAX_DAYS Maximum number of days a password may be used. +# PASS_MIN_DAYS Minimum number of days allowed between password changes. +# PASS_MIN_LEN Minimum acceptable password length. +# PASS_WARN_AGE Number of days warning given before a password expires. +# +PASS_MAX_DAYS 99999 +PASS_MIN_DAYS 0 +PASS_MIN_LEN 5 +PASS_WARN_AGE 7 + +# +# Min/max values for automatic uid selection in useradd +# +UID_MIN 1000 +UID_MAX 60000 +# System accounts +SYS_UID_MIN 201 +SYS_UID_MAX 999 + +# +# Min/max values for automatic gid selection in groupadd +# +GID_MIN 1000 +GID_MAX 60000 +# System accounts +SYS_GID_MIN 201 +SYS_GID_MAX 999 + +# +# If defined, this command is run when removing a user. +# It should remove any at/cron/print jobs etc. owned by +# the user to be removed (passed as the first argument). +# +#USERDEL_CMD /usr/sbin/userdel_local + +# +# If useradd should create home directories for users by default +# On RH systems, we do. This option is overridden with the -m flag on +# useradd command line. +# +CREATE_HOME yes + +# This enables userdel to remove user groups if no members exist. +# +USERGROUPS_ENAB yes + +# +# If set to SHA256, SHA256-based algorithm will be used for encrypting password +# If set to SHA512, SHA512-based algorithm will be used for encrypting password +# If set to BCRYPT, BCRYPT-based algorithm will be used for encrypting password +# +ENCRYPT_METHOD SHA512 + +# +# Only works if ENCRYPT_METHOD is set to SHA256 or SHA512. +# +# Define the number of SHA rounds. +# With a lot of rounds, it is more difficult to brute-force the password. +# However, more CPU resources will be needed to authenticate users if +# this value is increased. +# +# The values must be within the 1000-999999999 range. +# +SHA_CRYPT_MAX_ROUNDS 5000 + diff --git a/SOURCES/shadow-utils.useradd b/SOURCES/shadow-utils.useradd new file mode 100644 index 0000000..4e81146 --- /dev/null +++ b/SOURCES/shadow-utils.useradd @@ -0,0 +1,9 @@ +# useradd defaults file +GROUP=100 +HOME=/home +INACTIVE=-1 +EXPIRE= +SHELL=/bin/bash +SKEL=/etc/skel +CREATE_MAIL_SPOOL=yes + diff --git a/SPECS/shadow-utils.spec b/SPECS/shadow-utils.spec new file mode 100644 index 0000000..c9c1d5a --- /dev/null +++ b/SPECS/shadow-utils.spec @@ -0,0 +1,1375 @@ +Summary: Utilities for managing accounts and shadow password files +Name: shadow-utils +Version: 4.6 +Release: 22%{?dist} +Epoch: 2 +URL: http://pkg-shadow.alioth.debian.org/ +Source0: https://github.com/shadow-maint/shadow/releases/download/v%{version}/shadow-%{version}.tar.xz +Source1: https://github.com/shadow-maint/shadow/releases/download/v%{version}/shadow-%{version}.tar.xz.asc +Source2: shadow-utils.useradd +Source3: shadow-utils.login.defs +Source4: shadow-bsd.txt +Source5: https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + +### Globals ### +%global includesubiddir %{_includedir}/shadow + +### Patches ### +Patch0: shadow-4.6-redhat.patch +Patch1: shadow-4.6-goodname.patch +Patch2: shadow-4.1.5.1-info-parent-dir.patch +Patch6: shadow-4.6-selinux.patch +Patch10: shadow-4.6-orig-context.patch +Patch11: shadow-4.1.5.1-logmsg.patch +Patch14: shadow-4.1.5.1-default-range.patch +Patch15: shadow-4.6-manfix.patch +Patch17: shadow-4.1.5.1-userdel-helpfix.patch +Patch19: shadow-4.2.1-date-parsing.patch +Patch21: shadow-4.6-move-home.patch +Patch22: shadow-4.6-audit-update.patch +Patch23: shadow-4.5-usermod-unlock.patch +Patch24: shadow-4.2.1-no-lock-dos.patch +Patch28: shadow-4.6-selinux-perms.patch +Patch29: shadow-4.2.1-null-tm.patch +Patch31: shadow-4.6-getenforce.patch +Patch32: shadow-4.5-crypt_h.patch +Patch33: shadow-4.5-long-entry.patch +Patch34: shadow-4.6-usermod-crash.patch +Patch35: shadow-4.6-coverity.patch +Patch36: shadow-4.6-use-itstool.patch +Patch37: shadow-4.6-sssd-flush.patch +Patch38: shadow-4.6-sysugid-min-limit.patch +Patch39: shadow-4.6-chgrp-guard.patch +Patch40: shadow-4.6-ignore-login-prompt.patch +Patch41: shadow-4.6-use-lckpwdf.patch +# Upstreamed +Patch42: shadow-4.6-regular-user.patch +# Upstreamed +Patch43: shadow-4.6-home_mode-directive.patch +# Upstreamed +Patch44: shadow-4.6-check-local-groups.patch +# https://github.com/shadow-maint/shadow/commit/e84df9e163e133eb11a2728024ff3e3440592cf8 +Patch45: shadow-4.6-sssd-redirect-warning.patch +# Unused option in Fedora/RHEL - non upstreamable +Patch46: shadow-4.6-remove-login-string-references.patch +# https://github.com/shadow-maint/shadow/commit/e481437ab9ebe9a8bf8fbaabe986d42b2f765991 +Patch47: shadow-4.6-usermod-allow-all-group-types.patch +# https://github.com/shadow-maint/shadow/commit/0a7888b1fad613a052b988b01a71933b67296e68 +# https://github.com/shadow-maint/shadow/commit/607f1dd549cf9abc87af1cf29275f0d2d11eea29 +# https://github.com/shadow-maint/shadow/commit/b5fb1b38eea2fb0489ed088c82daf6700e72363e +# https://github.com/shadow-maint/shadow/commit/43a917cce54019799a8de037fd63780a2b640afc +Patch48: shadow-4.6-libsubid_creation.patch +# https://github.com/shadow-maint/shadow/commit/514c1328b6c90d817ae0a9f7addfb3c9a11a275a +# https://github.com/shadow-maint/shadow/commit/8492dee6632e340dee76eee895c3e30877bebf45 +# https://github.com/shadow-maint/shadow/commit/0f4347d1483191b2142546416a9eefe0c9459600 +Patch49: shadow-4.6-libsubid_nsswitch_support.patch +# https://github.com/shadow-maint/shadow/commit/186b1b7ac1a68d0fcc618a22da1a99232b420911 +Patch50: shadow-4.6-man-mention-nss-in-newuidmap.patch +# https://github.com/shadow-maint/shadow/commit/f9831a4a1a20b0e8fe47cc72ec20018ec04dbb90 +Patch51: shadow-4.6-libsubid_not_print_error_messages.patch +# https://github.com/shadow-maint/shadow/commit/c6cab4a7bafa18d9d65a333cac1261e7b5e32bc9 +Patch52: shadow-4.6-libsubid_init_return_false.patch +# https://github.com/shadow-maint/shadow/commit/2f1f45d64fc7c10e7a3cbe00e89f63714343e526 +Patch53: shadow-4.6-useradd_SUB_UID_COUNT-0.patch +# https://github.com/shadow-maint/shadow/commit/ea7af4e1543c63590d4107ae075fea385028997d +Patch54: shadow-4.6-libsubid_simplify_ranges_variable.patch +# https://github.com/shadow-maint/shadow/commit/0fe42f571c69f0105d31305f995c9887aeb9525e +Patch55: shadow-4.6-libsubid_init_not_print_error_messages.patch +# https://github.com/shadow-maint/shadow/commit/ec1951c181faed188464396b2cfdd2efb726c7f3 +Patch56: shadow-4.6-libsubid_fix_newusers_nss_provides_subids.patch +# https://github.com/shadow-maint/shadow/commit/087112244327be50abc24f9ec8afbf60ae8b2dec +# https://github.com/shadow-maint/shadow/pull/353 +Patch57: shadow-4.6-man_clarify_subid_delegation.patch +# https://github.com/shadow-maint/shadow/commit/bd920ab36a6c641e4a8769f8c7f8ca738ec61820 +Patch58: shadow-4.6-libsubid_make_logfd_not_extern.patch +# https://github.com/shadow-maint/shadow/commit/0dffc7c61200f492eeac03c29fa7e93b62d3cead +Patch59: shadow-4.6-useradd_dont_try_to_create_0_subuids.patch +# https://github.com/shadow-maint/shadow/commit/77e39de1e6cbd6925f16bb260abb7d216296886b +Patch60: shadow-4.6-install_subid_h.patch +# https://github.com/shadow-maint/shadow/commit/fa986b1d73605ecca54a4f19249227aeab827bf6 +Patch61: shadow-4.6-respect_enable_static_no.patch +# https://github.com/shadow-maint/shadow/commit/3b6ccf642c6bb2b7db087f09ee563ae9318af734 +Patch62: shadow-4.6-getsubids.patch +# https://github.com/shadow-maint/shadow/commit/a757b458ffb4fb9a40bcbb4f7869449431c67f83 +Patch63: shadow-4.6-groupdel-fix-sigsegv-when-passwd-does-not-exist.patch +# https://github.com/shadow-maint/shadow/commit/3ec32f9975f262073f8fbdecd2bfaee4a1d3db48 +Patch64: shadow-4.9-subordinateio-compare-owner-ID.patch +# https://github.com/shadow-maint/shadow/commit/e0524e813a3bae2891b33a66f35876841c11cee7 +Patch65: shadow-4.6-useradd-check-if-subid-range-exists.patch +# https://github.com/shadow-maint/shadow/commit/baae5b4a06c905d9f52ed1f922a0d7d0625d11cf +Patch66: shadow-4.6-skip-over-reserved-ids.patch +# https://github.com/shadow-maint/shadow/commit/65c88a43a23c2391dcc90c0abda3e839e9c57904 +Patch67: shadow-4.6-gpasswd-fix-password-leak.patch +Patch68: shadow-4.6-salt-remove-rounds.patch + +License: BSD and GPLv2+ +Group: System Environment/Base +BuildRequires: gcc +BuildRequires: libselinux-devel >= 1.25.2-1 +BuildRequires: audit-libs-devel >= 1.6.5 +BuildRequires: libsemanage-devel +BuildRequires: libacl-devel, libattr-devel +BuildRequires: bison, flex, docbook-style-xsl, docbook-dtds +BuildRequires: autoconf, automake, libtool, gettext-devel +BuildRequires: /usr/bin/xsltproc, /usr/bin/itstool +Requires: libselinux >= 1.25.2-1 +Requires: audit-libs >= 1.6.5 +Requires: setup +Requires(pre): coreutils +Requires(post): coreutils +Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) + +%description +The shadow-utils package includes the necessary programs for +converting UNIX password files to the shadow password format, plus +programs for managing user and group accounts. The pwconv command +converts passwords to the shadow password format. The pwunconv command +unconverts shadow passwords and generates a passwd file (a standard +UNIX password file). The pwck command checks the integrity of password +and shadow files. The lastlog command prints out the last login times +for all users. The useradd, userdel, and usermod commands are used for +managing user accounts. The groupadd, groupdel, and groupmod commands +are used for managing group accounts. + + +### Subpackages ### +%package subid +Summary: A library to manage subordinate uid and gid ranges +License: BSD and GPLv2+ + +%description subid +Utility library that provides a way to manage subid ranges. + + +%package subid-devel +Summary: Development package for shadow-utils-subid +License: BSD and GPLv2+ +Requires: shadow-utils-subid = %{epoch}:%{version}-%{release} + +%description subid-devel +Development files for shadow-utils-subid. + +%prep +%setup -q -n shadow-%{version} +%patch0 -p1 -b .redhat +%patch1 -p1 -b .goodname +%patch2 -p1 -b .info-parent-dir +%patch6 -p1 -b .selinux +%patch10 -p1 -b .orig-context +%patch11 -p1 -b .logmsg +%patch14 -p1 -b .default-range +%patch15 -p1 -b .manfix +%patch17 -p1 -b .userdel +%patch19 -p1 -b .date-parsing +%patch21 -p1 -b .move-home +%patch22 -p1 -b .audit-update +%patch23 -p1 -b .unlock +%patch24 -p1 -b .no-lock-dos +%patch28 -p1 -b .selinux-perms +%patch29 -p1 -b .null-tm +%patch31 -p1 -b .getenforce +%patch32 -p1 -b .crypt_h +%patch33 -p1 -b .long-entry +%patch34 -p1 -b .usermod-crash +%patch35 -p1 -b .coverity +%patch36 -p1 -b .use-itstool +%patch37 -p1 -b .sssd-flush +%patch38 -p1 -b .sysugid-min-limit +%patch39 -p1 -b .chgrp-guard +%patch40 -p1 -b .login-prompt +%patch41 -p1 -b .use-lckpwdf +%patch42 -p1 -b .regular-user +%patch43 -p1 -b .home_mode-directive +%patch44 -p1 -b .check-local-groups +%patch45 -p1 -b .sssd-redirect-warning +%patch46 -p1 -b .remove-login-string-references +%patch47 -p1 -b .usermod-allow-all-group-types +%patch48 -p1 -b .libsubid_creation +%patch49 -p1 -b .libsubid_nsswitch_support +%patch50 -p1 -b .man-mention-nss-in-newuidmap +%patch51 -p1 -b .libsubid_not_print_error_messages +%patch52 -p1 -b .libsubid_init_return_false +%patch53 -p1 -b .useradd_SUB_UID_COUNT-0 +%patch54 -p1 -b .libsubid_simplify_ranges_variable +%patch55 -p1 -b .libsubid_init_not_print_error_messages +%patch56 -p1 -b .libsubid_fix_newusers_nss_provides_subids +%patch57 -p1 -b .man_clarify_subid_delegation +%patch58 -p1 -b .libsubid_make_logfd_not_extern +%patch59 -p1 -b .useradd_dont_try_to_create_0_subuids +%patch60 -p1 -b .install_subid_h +%patch61 -p1 -b .respect_enable_static_no +%patch62 -p1 -b .getsubids +%patch63 -p1 -b .groupdel-fix-sigsegv-when-passwd-does-not-exist +%patch64 -p1 -b .subordinateio-compare-owner-ID +%patch65 -p1 -b .useradd-check-if-subid-range-exists +%patch66 -p1 -b .skip-over-reserved-ids +%patch67 -p1 -b .gpasswd-fix-password-leak +%patch68 -p1 -b .salt-remove-rounds + +iconv -f ISO88591 -t utf-8 doc/HOWTO > doc/HOWTO.utf8 +cp -f doc/HOWTO.utf8 doc/HOWTO + +cp -a %{SOURCE4} %{SOURCE5} . + +# Force regeneration of getdate.c +rm libmisc/getdate.c + +%build +%ifarch sparc64 +#sparc64 need big PIE +export CFLAGS="$RPM_OPT_FLAGS -fPIE" +export LDFLAGS="-pie -Wl,-z,relro -Wl,-z,now" +%else +export CFLAGS="$RPM_OPT_FLAGS -fpie" +export LDFLAGS="-pie -Wl,-z,relro -Wl,-z,now" +%endif + +autoreconf +%configure \ + --enable-shadowgrp \ + --enable-man \ + --with-audit \ + --with-sha-crypt \ + --with-selinux \ + --without-libcrack \ + --without-libpam \ + --enable-shared \ + --with-group-name-max-length=32 +%make_build + +%install +rm -rf $RPM_BUILD_ROOT +%make_install gnulocaledir=$RPM_BUILD_ROOT/%{_datadir}/locale MKINSTALLDIRS=`pwd`/mkinstalldirs +install -d -m 755 $RPM_BUILD_ROOT/%{_sysconfdir}/default +install -p -c -m 0644 %{SOURCE3} $RPM_BUILD_ROOT/%{_sysconfdir}/login.defs +install -p -c -m 0600 %{SOURCE2} $RPM_BUILD_ROOT/%{_sysconfdir}/default/useradd + + +ln -s useradd $RPM_BUILD_ROOT%{_sbindir}/adduser +ln -s useradd.8 $RPM_BUILD_ROOT/%{_mandir}/man8/adduser.8 +for subdir in $RPM_BUILD_ROOT/%{_mandir}/{??,??_??,??_??.*}/man* ; do + test -d $subdir && test -e $subdir/useradd.8 && echo ".so man8/useradd.8" > $subdir/adduser.8 +done + +# Remove binaries we don't use. +rm $RPM_BUILD_ROOT/%{_bindir}/chfn +rm $RPM_BUILD_ROOT/%{_bindir}/chsh +rm $RPM_BUILD_ROOT/%{_bindir}/expiry +rm $RPM_BUILD_ROOT/%{_bindir}/groups +rm $RPM_BUILD_ROOT/%{_bindir}/login +rm $RPM_BUILD_ROOT/%{_bindir}/passwd +rm $RPM_BUILD_ROOT/%{_bindir}/su +rm $RPM_BUILD_ROOT/%{_bindir}/faillog +rm $RPM_BUILD_ROOT/%{_sysconfdir}/login.access +rm $RPM_BUILD_ROOT/%{_sysconfdir}/limits +rm $RPM_BUILD_ROOT/%{_sbindir}/logoutd +rm $RPM_BUILD_ROOT/%{_sbindir}/nologin +rm $RPM_BUILD_ROOT/%{_mandir}/man1/chfn.* +rm $RPM_BUILD_ROOT/%{_mandir}/*/man1/chfn.* +rm $RPM_BUILD_ROOT/%{_mandir}/man1/chsh.* +rm $RPM_BUILD_ROOT/%{_mandir}/*/man1/chsh.* +rm $RPM_BUILD_ROOT/%{_mandir}/man1/expiry.* +rm $RPM_BUILD_ROOT/%{_mandir}/*/man1/expiry.* +rm $RPM_BUILD_ROOT/%{_mandir}/man1/groups.* +rm $RPM_BUILD_ROOT/%{_mandir}/*/man1/groups.* +rm $RPM_BUILD_ROOT/%{_mandir}/man1/login.* +rm $RPM_BUILD_ROOT/%{_mandir}/*/man1/login.* +rm $RPM_BUILD_ROOT/%{_mandir}/man1/passwd.* +rm $RPM_BUILD_ROOT/%{_mandir}/*/man1/passwd.* +rm $RPM_BUILD_ROOT/%{_mandir}/man1/su.* +rm $RPM_BUILD_ROOT/%{_mandir}/*/man1/su.* +rm $RPM_BUILD_ROOT/%{_mandir}/man5/limits.* +rm $RPM_BUILD_ROOT/%{_mandir}/*/man5/limits.* +rm $RPM_BUILD_ROOT/%{_mandir}/man5/login.access.* +rm $RPM_BUILD_ROOT/%{_mandir}/*/man5/login.access.* +rm $RPM_BUILD_ROOT/%{_mandir}/man5/passwd.* +rm $RPM_BUILD_ROOT/%{_mandir}/*/man5/passwd.* +rm $RPM_BUILD_ROOT/%{_mandir}/man5/porttime.* +rm $RPM_BUILD_ROOT/%{_mandir}/*/man5/porttime.* +rm $RPM_BUILD_ROOT/%{_mandir}/man5/suauth.* +rm $RPM_BUILD_ROOT/%{_mandir}/*/man5/suauth.* +rm $RPM_BUILD_ROOT/%{_mandir}/man8/logoutd.* +rm $RPM_BUILD_ROOT/%{_mandir}/*/man8/logoutd.* +rm $RPM_BUILD_ROOT/%{_mandir}/man8/nologin.* +rm $RPM_BUILD_ROOT/%{_mandir}/*/man8/nologin.* +rm $RPM_BUILD_ROOT/%{_mandir}/man3/getspnam.* +rm $RPM_BUILD_ROOT/%{_mandir}/*/man3/getspnam.* +rm $RPM_BUILD_ROOT/%{_mandir}/man5/faillog.* +rm $RPM_BUILD_ROOT/%{_mandir}/*/man5/faillog.* +rm $RPM_BUILD_ROOT/%{_mandir}/man8/faillog.* +rm $RPM_BUILD_ROOT/%{_mandir}/*/man8/faillog.* + +find $RPM_BUILD_ROOT%{_mandir} -depth -type d -empty -delete +%find_lang shadow +for dir in $(ls -1d $RPM_BUILD_ROOT%{_mandir}/{??,??_??}) ; do + dir=$(echo $dir | sed -e "s|^$RPM_BUILD_ROOT||") + lang=$(basename $dir) +# echo "%%lang($lang) $dir" >> shadow.lang +# echo "%%lang($lang) $dir/man*" >> shadow.lang + echo "%%lang($lang) $dir/man*/*" >> shadow.lang +done + +# Move header files to its own folder +mkdir -p $RPM_BUILD_ROOT/%{includesubiddir} +install -m 644 libsubid/subid.h $RPM_BUILD_ROOT/%{includesubiddir}/ + +# Remove .la files created by libsubid +rm -f $RPM_BUILD_ROOT/%{_libdir}/libsubid.la + +%files -f shadow.lang +%doc NEWS doc/HOWTO README +%{!?_licensedir:%global license %%doc} +%license gpl-2.0.txt shadow-bsd.txt +%attr(0644,root,root) %config(noreplace) %{_sysconfdir}/login.defs +%attr(0644,root,root) %config(noreplace) %{_sysconfdir}/default/useradd +%{_bindir}/sg +%attr(4755,root,root) %{_bindir}/chage +%attr(4755,root,root) %{_bindir}/gpasswd +%{_bindir}/lastlog +%attr(4755,root,root) %{_bindir}/newgrp +%attr(0755,root,root) %caps(cap_setgid=ep) %{_bindir}/newgidmap +%attr(0755,root,root) %caps(cap_setuid=ep) %{_bindir}/newuidmap +%{_sbindir}/adduser +%attr(0755,root,root) %{_sbindir}/user* +%attr(0755,root,root) %{_sbindir}/group* +%{_sbindir}/grpck +%{_sbindir}/pwck +%{_sbindir}/*conv +%{_sbindir}/chpasswd +%{_sbindir}/chgpasswd +%{_sbindir}/newusers +%{_sbindir}/vipw +%{_sbindir}/vigr +%{_mandir}/man1/chage.1* +%{_mandir}/man1/gpasswd.1* +%{_mandir}/man1/sg.1* +%{_mandir}/man1/newgrp.1* +%{_mandir}/man1/newgidmap.1* +%{_mandir}/man1/newuidmap.1* +%{_mandir}/man3/shadow.3* +%{_mandir}/man5/shadow.5* +%{_mandir}/man5/login.defs.5* +%{_mandir}/man5/gshadow.5* +%{_mandir}/man5/subuid.5* +%{_mandir}/man5/subgid.5* +%{_mandir}/man8/adduser.8* +%{_mandir}/man8/group*.8* +%{_mandir}/man8/user*.8* +%{_mandir}/man8/pwck.8* +%{_mandir}/man8/grpck.8* +%{_mandir}/man8/chpasswd.8* +%{_mandir}/man8/chgpasswd.8* +%{_mandir}/man8/newusers.8* +%{_mandir}/man8/*conv.8* +%{_mandir}/man8/lastlog.8* +%{_mandir}/man8/vipw.8* +%{_mandir}/man8/vigr.8* + +%files subid +%{_libdir}/libsubid.so.* +%{_bindir}/getsubids +%{_mandir}/man1/getsubids.1* + +%files subid-devel +%{includesubiddir}/subid.h +%{_libdir}/libsubid.so + +%changelog +* Tue Nov 21 2023 Iker Pedrosa - 2:4.6-22 +- salt: remove rounds from salt string. Resolves: RHEL-16668 + +* Thu Nov 2 2023 Iker Pedrosa - 2:4.6-21 +- login.defs: include SHA_CRYPT_MAX_ROUNDS. Resolves: RHEL-15024 + +* Wed Jul 12 2023 Iker Pedrosa - 2:4.6-19 +- gpasswd: fix password leak. Resolves: #2215947 + +* Wed May 17 2023 Iker Pedrosa - 2:4.6-18 +- Update patch to close label to reset libselinux state. Resolves: #1984740 +- useradd: check if subid range exists for user. Resolves: #2012929 +- find_new_[gu]id: Skip over IDs that are reserved for legacy reasons. Resolves: #1994269 + +* Thu Jul 21 2022 Iker Pedrosa - 2:4.6-17 +- subordinateio: also compare the owner ID. Resolves: #2093311 +- Fix release sources +- Add subid requirement for subid-devel + +* Thu Dec 9 2021 Iker Pedrosa - 2:4.6-16 +- getsubids: provide system binary and man page. Resolves: #2013016 +- groupdel: fix SIGSEGV when passwd does not exist. Resolves: #1986782 + +* Tue Oct 19 2021 Iker Pedrosa - 2:4.6-15 +- Creation of subid and subid-devel subpackages (#2013009) +- libsubid: creation and nsswitch support +- libsubid: don't print error messages on stderr by default +- libsubid: libsubid_init return false if out of memory +- libsubid: don't return owner in list_owner_ranges API call +- libsubid: libsubid_init don't print messages on error +- libsubid: fix newusers when nss provides subids +- libsubid: make shadow_logfd not extern +- useradd: fix SUB_UID_COUNT=0 +- man: mention NSS in new[ug]idmap manpages +- man: clarify subid delegation + +* Thu Aug 12 2021 Iker Pedrosa - 2:4.6-14 +- usermod: allow all group types with -G option (#1967641) + +* Mon May 3 2021 Iker Pedrosa - 2:4.6-13 +- man: Remove references to LOGIN_STRING in login.defs (#1884702) + +* Fri Oct 23 2020 Iker Pedrosa - 2:4.6-12 +- lib/sssd: redirect warning message to file (#1749001) +- useradd: clarify valid usernames/groupnames (#1869432) +- login.defs: link login specific information to its own package (#1804766) + +* Fri Aug 7 2020 Iker Pedrosa - 2:4.6-11 +- change UMASK value and add HOME_MODE in login.defs (#1777718) + +* Tue May 5 2020 Iker Pedrosa - 2:4.6-10 +- check only local groups when adding new supplementary groups to a user + +* Fri Apr 17 2020 Iker Pedrosa - 2:4.6-9 +- do not mistake a regular user process for a namespaced one (#1788696) +- add HOME_MODE support in login.defs (#1777718) + +* Fri Jun 7 2019 Tomáš Mráz - 2:4.6-8 +- properly audit group password change +- do not add uid of a new (not yet added) user to the audit message +- use lckpwdf() again to disable concurrent edits of databases by + other applications +- clarify chage manual page in regards to shadow and passwd + inconsistency +- fix minor issues in groupadd and login.defs manual pages +- Ignore LOGIN_PLAIN_PROMPT variable in login.defs +- force regeneration of getdate.c otherwise the date parsing fix + is not applied + +* Tue Dec 18 2018 Tomáš Mráz - 2:4.6-7 +- usermod: guard against unsafe change of ownership of + special home directories + +* Fri Nov 30 2018 Tomáš Mráz - 2:4.6-6 +- drop trailing space from login.defs ENCRYPT_METHOD setting + +* Mon Nov 19 2018 Tomáš Mráz - 2:4.6-5 +- use cap_setxid file capabilities for newxidmap instead of making them setuid +- limit the SYS_U/GID_MIN value to 1 as the algorithm does not work with 0 + and the 0 is always used by root anyway +- manual page improvements +- flush sssd caches - patch by Jakub Hrozek + +* Fri Oct 12 2018 Tomáš Mráz - 2:4.6-4 +- fix some issues from Coverity scan + +* Tue Jul 31 2018 Tomáš Mráz - 2:4.6-2 +- use itstool instead of xml2po + +* Tue Jul 31 2018 Tomáš Mráz - 2:4.6-1 +- Update to current upstream release 4.6 +- Raise limit for passwd and shadow entry length but also prevent + writing longer entries (#1422497) + +* Tue Feb 06 2018 Björn Esser - 2:4.5-9 +- Add patch to include crypt.h, if present +- Use %%make_{build,install} macros +- Refresh other patches for proper alignment + +* Sat Jan 20 2018 Björn Esser - 2:4.5-8 +- Rebuilt for switch to libxcrypt + +* Mon Nov 6 2017 Tomáš Mráz - 2:4.5-7 +- fix regression caused by the userdel-chroot patch (#1509978) + +* Thu Nov 2 2017 Tomáš Mráz - 2:4.5-6 +- fix userdel in chroot (#1316168) +- add useful chage -E example to chage manpage + +* Fri Sep 15 2017 Tomáš Mráz - 2:4.5-5 +- do not allow "." and ".." user names + +* Mon Aug 14 2017 Tomáš Mráz - 2:4.5-4 +- allow switching to secondary group without checking the membership + explicitly (patch from upstream) + +* Thu Aug 03 2017 Fedora Release Engineering - 2:4.5-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild + +* Thu Jul 27 2017 Fedora Release Engineering - 2:4.5-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild + +* Fri Jul 21 2017 Tomáš Mráz - 2:4.5-1 +- update to current upstream release 4.5 + +* Sat Feb 11 2017 Fedora Release Engineering - 2:4.3.1-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild + +* Thu Aug 25 2016 Tomáš Mráz - 2:4.3.1-2 +- fix regression in useradd - not processing defaults properly (#1369979) + +* Tue Aug 23 2016 Tomáš Mráz - 2:4.3.1-1 +- new upstream release fixing low impact security issue + +* Tue Jun 14 2016 Tomáš Mráz - 2:4.2.1-11 +- guard for localtime() and gmtime() failure + +* Mon May 30 2016 Tomáš Mráz - 2:4.2.1-10 +- chpasswd, chgpasswd: open audit when starting + +* Thu May 26 2016 Tomáš Mráz - 2:4.2.1-9 +- chgpasswd: do not remove it +- chpasswd, chgpasswd: add selinux_check_access call (#1336902) + +* Thu Mar 17 2016 Tomáš Mráz - 2:4.2.1-8 +- userdel: fix userdel -f with /etc/subuid present (#1316168) + +* Tue Feb 9 2016 Tomáš Mráz - 2:4.2.1-7 +- usermod: properly return error during password manipulation + +* Wed Feb 3 2016 Tomáš Mráz - 2:4.2.1-6 +- add possibility to clear or set lastlog record for user via lastlog + +* Fri Jan 8 2016 Tomáš Mráz - 2:4.2.1-5 +- do not use obscure permissions for binaries +- remove unused commands from login.defs(5) cross-reference + +* Fri Nov 6 2015 Tomáš Mráz - 2:4.2.1-4 +- document that groupmems is not setuid root +- document that expiration of the password after inactivity period + locks the user account completely + +* Thu Aug 27 2015 Tomáš Mráz - 2:4.2.1-3 +- unlock also passwords locked with passwd -l +- prevent breaking user entry by entering a password containing colon +- fix possible DoS when locking the database files for update +- properly use login.defs from the chroot in useradd + +* Fri Jun 19 2015 Fedora Release Engineering - 2:4.2.1-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild + +* Wed Nov 26 2014 Tomáš Mráz - 2:4.2.1-1 +- new upstream release with support for subordinate uids and gids + +* Tue Nov 25 2014 Tomáš Mráz - 2:4.1.5.1-22 +- small adjustments to the audit patch + +* Fri Oct 17 2014 Tomáš Mráz - 2:4.1.5.1-21 +- update auditing to cover more events and fix some incorrect audit + records - patch by Steve Grubb (#1151580) +- apply the same new allocation algorithm to uids as for gids + +* Wed Sep 10 2014 Tomas Mraz - 2:4.1.5.1-20 +- discard obsolete matchpathcon cache after semanage_commit() + +* Tue Sep 9 2014 Tomas Mraz - 2:4.1.5.1-19 +- disallow all-numeric user and group names (#1139318) + +* Fri Aug 29 2014 Tomas Mraz - 2:4.1.5.1-18 +- label the newly created home dir correctly (#1077809) +- mention that chage -d 0 forces password change (#1135010) +- improve date parsing and error detecting in chage +- avoid full group database scanning in newgrp in most common case +- report error if usermod asked for moving homedir and it does not exist + +* Mon Aug 18 2014 Fedora Release Engineering - 2:4.1.5.1-17 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild + +* Tue Aug 5 2014 Tom Callaway - 2:4.1.5.1-16 +- fix license handling + +* Mon Jul 14 2014 Tomas Mraz - 2:4.1.5.1-15 +- revert the last change as it is not really needed + +* Thu Jul 10 2014 Tomas Mraz - 2:4.1.5.1-14 +- put system users and groups into /usr/lib/{passwd,group} if + the files exist and SHADOW_USE_USRLIB environment variable is set + Patch by Colin Walters + +* Mon Jun 30 2014 Tomas Mraz - 2:4.1.5.1-13 +- ignore getgrgid() errors for now + +* Mon Jun 30 2014 Tomas Mraz - 2:4.1.5.1-12 +- improve group allocation algorithm - patch by Stephen Gallager (#1089738) + +* Sun Jun 08 2014 Fedora Release Engineering - 2:4.1.5.1-11 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild + +* Wed Feb 12 2014 Tomas Mraz - 2:4.1.5.1-10 +- clean up login.defs manpage +- properly document userdel -f behavior + +* Fri Oct 18 2013 Tomas Mraz - 2:4.1.5.1-9 +- document that the directory where user's home is created must exist + +* Thu Jul 25 2013 Tomas Mraz - 2:4.1.5.1-8 +- slightly more meaningful error messages if crypt() returns NULL (#988184) +- explicit suid permissions + +* Fri Jul 19 2013 Tomas Mraz - 2:4.1.5.1-7 +- fix useradd man page bugs + +* Fri Jun 14 2013 Tomas Mraz - 2:4.1.5.1-6 +- report error to stdout when SELinux context for home directory + cannot be determined (#973647) +- audit the changing home directory owner (#885797) +- do not set the default SELinux MLS range (#852676) + +* Tue Mar 19 2013 Tomas Mraz - 2:4.1.5.1-5 +- improve the failure syslog message in useradd (#830617) + +* Wed Feb 20 2013 Tomas Mraz - 2:4.1.5.1-4 +- keep the original context if matchpathcon() fails (#912399) + +* Tue Jan 29 2013 Tomas Mraz - 2:4.1.5.1-3 +- fix bugs in merge_group_entries() + +* Fri Jan 11 2013 Tomas Mraz - 2:4.1.5.1-2 +- /etc/default is owned by glibc-common now (#894194) + +* Wed Sep 19 2012 Tomas Mraz - 2:4.1.5.1-1 +- new upstream version +- use the original file permissions when creating backup (#853102) + +* Wed Jul 25 2012 Peter Vrabec - 2:4.1.5-5 +- make /etc/default/useradd world-readable (#835137) + +* Sat Jul 21 2012 Fedora Release Engineering - 2:4.1.5-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Mon Jun 18 2012 Peter Vrabec - 2:4.1.5-3 +- pwconv/grpconv skipped 2nd of consecutive failures (#832995) + +* Thu Mar 22 2012 Peter Vrabec - 2:4.1.5-2 +- fix selinux context handling +- reset selinux context on files copied from skel + +* Mon Mar 19 2012 Peter Vrabec - 2:4.1.5-1 +- upgrade + +* Tue Feb 07 2012 Peter Vrabec - 2:4.1.4.3-14 +- compile with PIE and RELRO flags (#784349) + +* Sat Jan 14 2012 Fedora Release Engineering - 2:4.1.4.3-13 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild + +* Tue Dec 20 2011 Peter Vrabec - 2:4.1.4.3-12 +- fix leaks in .IDs patch (#734340) + +* Wed Nov 16 2011 Peter Vrabec - 2:4.1.4.3-11 +- free memory associated with SELinux security contexts + +* Wed Nov 09 2011 Peter Vrabec - 2:4.1.4.3-10 +- replace semanage call by library call +- useradd man page (#739147) + +* Tue Aug 02 2011 Peter Vrabec - 2:4.1.4.3-9 +- man page adjustment (userdel -Z) + +* Tue Aug 02 2011 Peter Vrabec - 2:4.1.4.3-8 +- fixing semanage issue (#701355) + +* Fri Jul 22 2011 Miloslav Trmač - 2:4.1.4.3-7 +- Make sure /etc/login.defs is not changed on upgrades from Fedora 1[345]. + +* Wed Jun 29 2011 Peter Vrabec - 2:4.1.4.3-6 +- man page fixes (#696213 #674878) + +* Tue Jun 28 2011 Peter Vrabec - 2:4.1.4.3-5 +- userdel option to remove Linux login <-> SELinux login mapping (#639900) +- useradd special exit value if SELinux user mapping is invalid (#639975) +- usermod special exit value if SELinux user mapping is invalid (#639976) + +* Mon Jun 27 2011 Peter Vrabec - 2:4.1.4.3-4 +- refer to PAM in /etc/login.defs (#629277) + +* Mon Jun 06 2011 Peter Vrabec - 2:4.1.4.3-3 +- fix shadow-4.1.4.2-underflow.patch + +* Tue May 31 2011 Peter Vrabec - 2:4.1.4.3-2 +- fix integer underflow in laslog (#706321) + +* Fri May 20 2011 Peter Vrabec - 2:4.1.4.3-1 +- upgrade +- change UID/GID_MIN to #1000 +- fix find_new_uid/gid for big UID/GID_MAX + +* Wed Feb 09 2011 Peter Vrabec - 2:4.1.4.2-11 +- useradd man page (-m option) +- create home directory on fs with noacl +- remove faillog app (pam_tally.so is no longer shipped) + Resolves: #523265, #622320 + +* Tue Feb 01 2011 Peter Vrabec - 2:4.1.4.2-10 +- do not use gshadow functions from glibc, there is a bug + in glibc sgetsgent(#674361) + Resolves: #674234 + +* Wed Jan 05 2011 Peter Vrabec - 2:4.1.4.2-9 +- fix gshadow functions from shadow utils +- make shadow utils use gshadow functions from glibc + Resolves: #665780 + +* Tue Jul 20 2010 Peter Vrabec - 2:4.1.4.2-8 +- fix pwck/grpck hang + Resolves: #586322 + +* Mon Jun 14 2010 Peter Vrabec - 2:4.1.4.2-7 +- fix integer underflow in faillog (#603683) +- use preferred GID for reserved static IDs + +* Thu Apr 29 2010 Peter Vrabec - 2:4.1.4.2-6 +- preserve ACL's on files in /etc/skel + Resolves: #513055 + +* Wed Apr 28 2010 Peter Vrabec - 2:4.1.4.2-5 +- newusers man page more informative +- userdel should not need to run semanage + Resolves: #586330 #586408 + +* Thu Apr 01 2010 Peter Vrabec - 2:4.1.4.2-4 +- fix man directories ownership (#569418) + +* Fri Mar 26 2010 Peter Vrabec - 2:4.1.4.2-3 +- max group name length set to 32 characters + +* Wed Nov 18 2009 Peter Vrabec - 2:4.1.4.2-2 +- apply patches{1,2,3} +- enable SHA512 in /etc/login.defs + +* Mon Sep 07 2009 Peter Vrabec - 2:4.1.4.2-1 +- upgrade + +* Fri Aug 21 2009 Tomas Mraz - 2:4.1.4.1-7 +- rebuilt with new audit + +* Wed Aug 05 2009 Peter Vrabec 2:4.1.4.1-6 +- increase threshold for uid/gid reservations to 200 (#515667) + +* Sun Jul 26 2009 Fedora Release Engineering - 2:4.1.4.1-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild + +* Thu Jul 16 2009 Peter Vrabec 2:4.1.4.1-4 +- fix a list of owned directories (#510366) + +* Thu Jul 16 2009 Peter Vrabec 2:4.1.4.1-3 +- reduce the reuse of system IDs + +* Wed Jul 15 2009 Peter Vrabec 2:4.1.4.1-2 +- speed up sys users look up on LDAP boxes (#511813) + +* Tue Jun 16 2009 Peter Vrabec 2:4.1.4.1-1 +- upgrade + +* Fri May 15 2009 Peter Vrabec 2:4.1.4-1 +- upgrade + +* Wed Apr 22 2009 Peter Vrabec 2:4.1.3.1-2 +- lastlog fix + +* Fri Apr 17 2009 Peter Vrabec 2:4.1.3.1-1 +- upgrade + +* Tue Apr 14 2009 Peter Vrabec 2:4.1.3-2 +- get "-n" option back +- fix selinux issues + +* Tue Apr 14 2009 Peter Vrabec 2:4.1.3-1 +- upgrade + +* Tue Mar 24 2009 Peter Vrabec 2:4.1.2-12 +- don not allow UID/GID = 4294967295 (#484040) + +* Mon Jan 19 2009 Peter Vrabec 2:4.1.2-11 +- fix license tag (#226416) +- get rid of tabs in spec file (#226416) +- convert HOWTO to UTF8 (#226416) + +* Mon Jan 05 2009 Peter Vrabec 2:4.1.2-10 +- Add policycoreutils as Requires, because of restorecon (#478494) + +* Sun Dec 21 2008 Jesse Keating - 2:4.1.2-9 +- Add setup as a Requires. Perhaps this should be a files requires. (#477529) + +* Wed Sep 24 2008 Peter Vrabec 2:4.1.2-8 +- groupmems: check username for valid character (#455603) +- groupmems: don't segfault on nonexistent group (#456088) + +* Thu Sep 11 2008 Peter Vrabec 2:4.1.2-7 +- fix usermod SELinux user mappings change (#458766) + +* Tue Sep 02 2008 Peter Vrabec 2:4.1.2-6 +- audit improvements, thnx. to sgrubb@redhat.com + +* Tue Sep 02 2008 Peter Vrabec 2:4.1.2-5 +- fix groupmems issues (#459825) + +* Mon Jul 28 2008 Peter Vrabec 2:4.1.2-4 +- fix configure options (#456748) + +* Thu Jul 24 2008 Peter Vrabec 2:4.1.2-3 +- recreate selinux patch + +* Tue Jul 22 2008 Peter Vrabec 2:4.1.2-2 +- provide getspnam by man-pages + +* Mon May 26 2008 Peter Vrabec 2:4.1.2-1 +- upgrade + +* Tue May 20 2008 Peter Vrabec 2:4.1.1-2 +- fix salt size problem (#447136) + +* Mon Apr 07 2008 Peter Vrabec 2:4.1.1-1 +- upgrade + +* Fri Mar 07 2008 Peter Vrabec 2:4.1.0-5 +- improve newgrp audit patch + +* Mon Mar 03 2008 Peter Vrabec 2:4.1.0-4 +- fix selinux labeling (#433757) + +* Tue Feb 19 2008 Peter Vrabec 2:4.1.0-3 +- fix groupmems segmentation fault (#430813) + +* Wed Feb 13 2008 Peter Vrabec 2:4.1.0-2 +- fix newgrp audit event + +* Wed Dec 12 2007 Peter Vrabec 2:4.1.0-1 +- new upgrade release from new upstream +- provide vipw and vigr + +* Thu Nov 29 2007 Peter Vrabec 2:4.0.18.1-20 +- do not create mail spool entries for system accounts (#402351) + +* Thu Oct 18 2007 Peter Vrabec 2:4.0.18.1-19 +- fix timestamps when moving home dirs to another file system (#278571) + +* Mon Oct 08 2007 Peter Vrabec 2:4.0.18.1-18 +- mark localized man pages with %%lang + +* Wed Aug 22 2007 Peter Vrabec 2:4.0.18.1-17 +- rebuild + +* Tue Jun 26 2007 Peter Vrabec 2:4.0.18.1-16 +- fix "CAVEATS" section of groupadd man page (#245590) + +* Wed Jun 06 2007 Peter Vrabec 2:4.0.18.1-15 +- fix infinitive loop if there are duplicate entries + in /etc/group (#240915) + +* Wed Jun 06 2007 Peter Vrabec 2:4.0.18.1-14 +- do not run find_new_uid() twice and use getpwuid() to check + UID uniqueness (#236871) + +* Tue Apr 10 2007 Peter Vrabec 2:4.0.18.1-13 +- fix useradd dump core when build without WITH_SELINUX (#235641) + +* Mon Mar 26 2007 Peter Vrabec 2:4.0.18.1-12 +- create user's mailbox file by default (#231311) + +* Fri Mar 16 2007 Peter Vrabec 2:4.0.18.1-11 +- assign system dynamic UID/GID from the top of available UID/GID (#190523) + +* Wed Feb 28 2007 Peter Vrabec 2:4.0.18.1-10 +- spec file fixes to meet fedora standarts. +- fix useless call of restorecon(). (#222159) + +* Sun Jan 14 2007 Peter Vrabec 2:4.0.18.1-9 +- fix append option in usermod (#222540). + +* Thu Dec 21 2006 Dan Walsh 2:4.0.18.1-8 +- Fix execution and creation of Home Directories under SELinux +- Resolves: rhbz#217441 + +* Thu Dec 14 2006 Peter Vrabec 2:4.0.18.1-7 +- fix rpmlint issues + +* Wed Dec 06 2006 Peter Vrabec 2:4.0.18.1-6 +- use MD5 encryption by default (#218629). + +* Thu Nov 30 2006 Steve Grubb 2:4.0.18.1-5 +- Fix SELinux context on home directories created with useradd (#217441) + +* Tue Nov 14 2006 Peter Vrabec 2:4.0.18.1-4 +- fix chpasswd and chgpasswd stack overflow (#213052) + +* Sat Nov 04 2006 Peter Vrabec 2:4.0.18.1-3 +- fix "-g" and "-G" option. + +* Fri Nov 03 2006 Peter Vrabec 2:4.0.18.1-2 +- improve audit logging (#211659) +- improve "-l" option. Do not reset faillog if it's used (#213450). + +* Wed Nov 01 2006 Peter Vrabec 2:4.0.18.1-1 +- upgrade + +* Wed Oct 25 2006 Peter Vrabec 2:4.0.17-7 +- add dist-tag + +* Wed Oct 04 2006 Peter Vrabec 2:4.0.17-6 +- fix regression. Permissions on user* group* binaries + should be 0750, because of CAPP/LSPP certification +- fix groupdel man page + +* Fri Aug 11 2006 Peter Vrabec 2:4.0.17-5 +- fix bug introduced with UIG_GID.patch (#201991) + +* Sat Aug 05 2006 Peter Vrabec 2:4.0.17-4 +- fix userdel, it didn't delete user's group (#201379) + +* Fri Aug 04 2006 Peter Vrabec 2:4.0.17-3 +- fix UID/GID overflow in user* group* (#198920) + +* Fri Aug 04 2006 Peter Vrabec 2:4.0.17-2 +- do not inherit file desc. in execve(nscd) + +* Mon Jul 17 2006 Peter Vrabec 2:4.0.17-1 +- upgrade + +* Wed Jul 12 2006 Jesse Keating - 2:4.0.16-3.1 +- rebuild + +* Tue Jun 13 2006 Peter Vrabec 2:4.0.16-3 +- call "nscd -i" to flush nscd cache (#191464) + +* Sat Jun 10 2006 Peter Vrabec 2:4.0.16-2 +- "useradd -r" must create a system group (#194728) + +* Tue Jun 06 2006 Peter Vrabec 2:4.0.16-1 +- upgrade +- do not replace login.defs file (#190014) + +* Sat Apr 08 2006 Peter Vrabec 2:4.0.15-3 +- fix typo in shadow-4.0.15-login.defs (#188263) + +* Tue Apr 04 2006 Peter Vrabec 2:4.0.15-2 +- properly notify nscd to flush its cache(#186803) + +* Mon Apr 03 2006 Peter Vrabec 2:4.0.15-1 +- upgrade + +* Fri Mar 10 2006 Peter Vrabec 2:4.0.14-4 +- fix lrename() function to handle relative symlinks too + +* Tue Mar 07 2006 Peter Vrabec 2:4.0.14-3 +- set default umask to 077 in login.defs + +* Mon Mar 06 2006 Peter Vrabec 2:4.0.14-2 +- use lrename() function, which follow a destination symbolic link(#181977) + +* Fri Feb 10 2006 Jesse Keating - 2:4.0.14-1.2 +- bump again for double-long bug on ppc(64) + +* Tue Feb 07 2006 Jesse Keating - 2:4.0.14-1.1 +- rebuilt for new gcc4.1 snapshot and glibc changes + +* Fri Jan 06 2006 Peter Vrabec 2:4.0.14-1 +- upgrade + +* Fri Dec 09 2005 Jesse Keating +- rebuilt + +* Tue Nov 29 2005 Peter Vrabec 2:4.0.13-4 +- fix incorrect audit record in userdel (#174392) + +* Wed Nov 16 2005 Peter Vrabec 2:4.0.13-3 +- fix useradd segfaults (#173241) + +* Sat Nov 5 2005 Steve Grubb 2:4.0.13-2 +- Update audit communication to standard format messages + +* Fri Oct 21 2005 Peter Vrabec 2:4.0.13-1 +- upgrade + +* Fri Sep 23 2005 Peter Vrabec 2:4.0.12-4 +- add useradd -l option back, it was removed by mistake + +* Tue Sep 20 2005 Peter Vrabec 2:4.0.12-3 +- provide login.defs man page +- adjust audit patch + +* Tue Aug 30 2005 Peter Vrabec 2:4.0.12-2 +- audit support + +* Sat Aug 27 2005 Peter Vrabec 2:4.0.12-1 +- upgrade + +* Sat Aug 13 2005 Dan Walsh 2:4.0.11.1-5 +- Change to use new selinux api for selinux_check_passwd_access + +* Tue Aug 09 2005 Peter Vrabec 2:4.0.11.1-4 +- change the password last changed field in the shadow file + when "usermod -p" is used (#164943) + +* Mon Aug 08 2005 Peter Vrabec 2:4.0.11.1-3 +- provide getspnam.3 man page(#162476) +- fix useradd man page(#97131) + +* Mon Aug 08 2005 Peter Vrabec 2:4.0.11.1-2 +- do not copy files from skel directory if home directory + already exist (#89591,#80242) + +* Fri Aug 05 2005 Peter Vrabec 2:4.0.11.1-1 +- upgrade + +* Mon May 23 2005 Peter Vrabec 2:4.0.7-9 +- remove vigr binary + +* Mon May 23 2005 Peter Vrabec 2:4.0.7-8 +- fix nscd socket path + +* Fri Apr 29 2005 Jeremy Katz - 2:4.0.7-7 +- don't assume selinux is enabled if is_selinux_enabled() returns -1 + +* Mon Apr 18 2005 Peter Vrabec 2:4.0.7-6 +- fix chage -l option (#109499, #137498) + +* Mon Apr 04 2005 Peter Vrabec 2:4.0.7-5 +- fix memory leak, and CPU spinning when grp_update() and + duplicate group entries in /etc/group (#151484) + +* Tue Mar 29 2005 Peter Vrabec 2:4.0.7-4 +- use newgrp binary +- newgrp don't ask for password if user's default GID = group ID, + ask for password if there is some in /etc/gshadow + and in /etc/group is 'x' (#149997) + +* Mon Mar 14 2005 Peter Vrabec +- gcc4 fix (#150994) 2:4.0.7-3 + +* Mon Mar 07 2005 Peter Vrabec +- man pages cs,es,ko,ru,zh_CN,zh_TW to UTF-8 + +* Wed Mar 02 2005 Peter Vrabec +- upgrade 2:4.0.7-1 + +* Fri Feb 25 2005 Peter Vrabec 2:4.0.3-59 +- static limit on group count to dynamic (#125510, #148994, #147742) + +* Mon Feb 21 2005 Peter Vrabec 2:4.0.3-58 +- add "-l" option #146214 + +* Mon Feb 14 2005 Adrian Havill +- rebuilt + +* Wed Feb 9 2005 Dan Walsh 2:4.0.3-39 +- Change useradd to use matchpathcon + +* Thu Oct 21 2004 Dan Walsh 2:4.0.3-37 +- Add matchpathcon to create the files correctly when they do not exist. + +* Mon Oct 18 2004 Miloslav Trmac - 2:4.0.3-36 +- Change symlink ownership when copying from /etc/skel (#66819, patch by + Michael Weiser) + +* Fri Oct 15 2004 Adrian Havill 2:4.0.3-35 +- make the limit for the group name the same as the username (determined + by the header files, rather than a constant) (#56850) + +* Wed Oct 13 2004 Adrian Havill 2:4.0.3-33 +- allow for mixed case and dots in usernames (#135401) +- all man pages to UTF-8, not just Japanese (#133883) +- add Polish blurb for useradd -n man page option (#82177) + +* Tue Oct 12 2004 Adrian Havill 2:4.0.3-31 +- check for non-standard legacy place for ncsd HUP (/var/run/nscd.pid) and + then the std FHS place (/var/run/nscd.pid) (#125421) + +* Fri Oct 1 2004 Dan Walsh 2:4.0.3-30 +- Add checkPasswdAccess for chage in SELinux + +* Sun Sep 26 2004 Adrian Havill 2:4.0.3-29 +- always unlock all files on any exit (#126709) + +* Tue Aug 24 2004 Warren Togami 2:4.0.3-26 +- #126596 fix Req and BuildReqs + +* Sun Aug 1 2004 Alan Cox 4.0.3-25 +- Fix build deps etc, move to current auto* (Steve Grubb) + +* Sat Jul 10 2004 Alan Cox 4.0.3-24 +- Fix nscd path. This fixes various stale data caching bugs (#125421) + +* Thu Jun 17 2004 Dan Walsh 4.0.3-23 +- Add get_enforce checks +- Clean up patch for potential upstream submission +- Add removemalloc patch to get it to build on 3.4 + +* Tue Jun 15 2004 Elliot Lee +- rebuilt + +* Tue Mar 30 2004 Nalin Dahyabhai 4.0.3-21 +- rebuild + +* Tue Mar 30 2004 Nalin Dahyabhai 4.0.3-20 +- make /etc/default world-readable, needed for #118338 + +* Fri Feb 13 2004 Elliot Lee +- rebuilt + +* Wed Jan 21 2004 Dan Walsh 4.0.3-18 +- Fix selinux relabel of /etc/passwd file + +* Wed Jan 7 2004 Nalin Dahyabhai 4.0.3-17 +- fix use of uninitialized memory in useradd (#89145) + +* Tue Dec 16 2003 Nalin Dahyabhai 4.0.3-16 +- back to UTF-8 again +- remove getspnam(3) man page, now conflicts with man-pages 1.64 + +* Thu Nov 13 2003 Nalin Dahyabhai 4.0.3-15 +- don't convert man pages to UTF-8 for RHEL 3, conditionalized using macro +- fixup dangling man page references + +* Mon Nov 10 2003 Nalin Dahyabhai 4.0.3-14 +- lastlog: don't pass a possibly-smaller field to localtime (#109648) +- configure: call AC_SYS_LARGEFILE to get large file support + +* Fri Nov 7 2003 Dan Walsh 4.0.3-13.sel +- turn on SELinux support + +* Wed Oct 22 2003 Nalin Dahyabhai 4.0.3-12 +- convert ja man pages to UTF-8 (#106051) +- override MKINSTALLDIRS at install-time (#107476) + +* Mon Sep 8 2003 Dan Walsh +- turn off SELinux support + +* Thu Sep 4 2003 Dan Walsh 4.0.3-11.sel +- build with SELinux support + +* Mon Jul 28 2003 Dan Walsh 4.0.3-10 +- Add SELinux support + +* Wed Jun 04 2003 Elliot Lee +- rebuilt + +* Wed Jun 4 2003 Nalin Dahyabhai 4.0.3-8 +- rebuild + +* Tue Jun 3 2003 Nalin Dahyabhai 4.0.3-7 +- run autoconf to generate updated configure at compile-time + +* Wed Feb 12 2003 Nalin Dahyabhai 4.0.3-6 +- adjust mailspool patch to complain if no group named "mail" exists, even + though that should never happen + +* Tue Feb 11 2003 Nalin Dahyabhai 4.0.3-5 +- fix perms on mailspools created by useradd to be owned by the "mail" + group (#59810) + +* Wed Jan 22 2003 Tim Powers +- rebuilt + +* Mon Dec 9 2002 Nalin Dahyabhai 4.0.3-3 +- install the shadow.3 man page + +* Mon Nov 25 2002 Nalin Dahyabhai 4.0.3-2 +- disable use of cracklib at build-time +- fixup reserved-account changes for useradd + +* Thu Nov 21 2002 Nalin Dahyabhai 4.0.3-1 +- update to 4.0.3, bumping epoch + +* Mon Nov 18 2002 Nalin Dahyabhai 20000902-14 +- remove man pages which conflict with the man-pages package(s) + +* Fri Nov 15 2002 Nalin Dahyabhai 20000902-13 +- prevent libshadow from being built more than once, to keep automake happy +- change how md5 and md5crypt are enabled, to keep autoconf happy +- remove unpackaged files after %%install + +* Thu Aug 29 2002 Nalin Dahyabhai 20000902-12 +- force .mo files to be regenerated with current gettext to flush out possible + problems +- fixup non-portable encodings in translations +- make sv translation header non-fuzzy so that it will be included (#71281) + +* Fri Aug 23 2002 Nalin Dahyabhai 20000902-11 +- don't apply aging parameters when creating system accounts (#67408) + +* Fri Jun 21 2002 Tim Powers +- automated rebuild + +* Sun May 26 2002 Tim Powers +- automated rebuild + +* Fri May 17 2002 Nalin Dahyabhai 20000902-8 +- rebuild in new environment + +* Wed Mar 27 2002 Nalin Dahyabhai 20000902-7 +- rebuild with proper defines to get support for large lastlog files (#61983) + +* Fri Feb 22 2002 Nalin Dahyabhai 20000902-6 +- rebuild + +* Fri Jan 25 2002 Nalin Dahyabhai 20000902-5 +- fix autoheader breakage and random other things autotools complain about + +* Mon Aug 27 2001 Nalin Dahyabhai 20000902-4 +- use -O0 instead of -O on ia64 +- build in source directory +- don't leave lock files on the filesystem when useradd creates a group for + the user (#50269) +- fix the -o option to check for duplicate UIDs instead of login names (#52187) + +* Thu Jul 26 2001 Bill Nottingham 20000902-3 +- build with -O on ia64 + +* Fri Jun 08 2001 Than Ngo 20000902-2 +- fixup broken specfile + +* Tue May 22 2001 Bernhard Rosenkraenzer 20000902-1 +- Create an empty mailspool when creating a user so non-setuid/non-setgid + MDAs (postfix+procmail) can deliver mail (#41811) +- 20000902 +- adapt patches + +* Fri Mar 9 2001 Nalin Dahyabhai +- don't overwrite user dot files in useradd (#19982) +- truncate new files when moving overwriting files with the contents of other + files while moving directories (keeps files from looking weird later on) +- configure using %%{_prefix} as the prefix + +* Fri Feb 23 2001 Trond Eivind Glomsrxd +- langify + +* Wed Aug 30 2000 Bernhard Rosenkraenzer +- Fix up chage behavior (Bug #15883) + +* Wed Aug 30 2000 Bernhard Rosenkraenzer +- 20000826 +- Fix up useradd man page (Bug #17036) + +* Tue Aug 8 2000 Bernhard Rosenkraenzer +- check for vipw lock before adding or deleting users (Bug #6489) + +* Mon Aug 7 2000 Nalin Dahyabhai +- take LOG_CONS out of the openlog() call so that we don't litter the + screen during text-mode upgrades + +* Tue Jul 18 2000 Bernhard Rosenkraenzer +- Remove a fixed-size buffer that caused problems when adding a huge number + of users to a group (>8192 bytes) (Bugs #3809, #11930) + +* Tue Jul 18 2000 Bernhard Rosenkraenzer +- remove dependency on util-linux because it causes prereq loops + +* Tue Jul 18 2000 Nalin Dahyabhai +- change symlinked man pages to includers +- require /usr/bin/newgrp (util-linux) so that /usr/bin/sg isn't left dangling + +* Wed Jul 12 2000 Prospector +- automatic rebuild + +* Sun Jun 18 2000 Matt Wilson +- use mandir for FHS +- added patches in src/ and po/ to honor DESTDIR +- use make install DESTDIR=$RPM_BUILD_ROOT + +* Wed Feb 16 2000 Bernhard Rosenkraenzer +- Fix up usermod's symlink behavior (Bug #5458) + +* Fri Feb 11 2000 Cristian Gafton +- get rid of mkpasswd + +* Mon Feb 7 2000 Nalin Dahyabhai +- fix usermod patch to check for shadow before doing any shadow-specific stuff + and merge it into the pwlock patch + +* Sat Feb 5 2000 Bernhard Rosenkraenzer +- fix man symlinks + +* Wed Feb 2 2000 Nalin Dahyabhai +- make -p only change shadow password (bug #8923) + +* Mon Jan 31 2000 Cristian Gafton +- rebuild to fix dependeencies +- man pages are compressed + +* Wed Jan 19 2000 Bernhard Rosenkraenzer +- Fix a security bug (adduser could overwrite previously existing + groups, Bug #8609) + +* Sun Jan 9 2000 Bernhard Rosenkraenzer +- unset LINGUAS before building +- Fix typo in newusers manpage (Bug #8258) +- libtoolize + +* Wed Sep 22 1999 Cristian Gafton +- fix segfault for userdel when the primary group for the user is not + defined + +* Tue Sep 21 1999 Cristian Gafton +- Serial: 1 because now we are using 19990827 (why the heck can't they have + a normal version just like everybody else?!) +- ported all patches to the new code base + +* Thu Apr 15 1999 Bill Nottingham +- SIGHUP nscd from usermod, too + +* Fri Apr 09 1999 Michael K. Johnson +- added usermod password locking from Chris Adams + +* Thu Apr 08 1999 Bill Nottingham +- have things that modify users/groups SIGHUP nscd on exit + +* Wed Mar 31 1999 Michael K. Johnson +- have userdel remove user private groups when it is safe to do so +- allow -f to force user removal even when user appears busy in utmp + +* Tue Mar 23 1999 Preston Brown +- edit out unused CHFN fields from login.defs. + +* Sun Mar 21 1999 Cristian Gafton +- auto rebuild in the new build environment (release 7) + +* Wed Jan 13 1999 Bill Nottingham +- configure fix for arm + +* Wed Dec 30 1998 Cristian Gafton +- build against glibc 2.1 + +* Fri Aug 21 1998 Jeff Johnson +- Note that /usr/sbin/mkpasswd conflicts with /usr/bin/mkpasswd; + one of these (I think /usr/sbin/mkpasswd but other opinions are valid) + should probably be renamed. In any case, mkpasswd.8 from this package + needs to be installed. (problem #823) + +* Fri May 08 1998 Prospector System +- translations modified for de, fr, tr + +* Tue Apr 21 1998 Cristian Gafton +- updated to 980403 +- redid the patches + +* Tue Dec 30 1997 Cristian Gafton +- updated the spec file +- updated the patch so that new accounts created on shadowed system won't + confuse pam_pwdb anymore ('!!' default password instead on '!') +- fixed a bug that made useradd -G segfault +- the check for the ut_user is now patched into configure + +* Thu Nov 13 1997 Erik Troan +- added patch for XOPEN oddities in glibc headers +- check for ut_user before checking for ut_name -- this works around some + confusion on glibc 2.1 due to the utmpx header not defining the ut_name + compatibility stuff. I used a gross sed hack here because I couldn't make + automake work properly on the sparc (this could be a glibc 2.0.99 problem + though). The utuser patch works fine, but I don't apply it. +- sleep after running autoconf + +* Thu Nov 06 1997 Cristian Gafton +- added forgot lastlog command to the spec file + +* Mon Oct 27 1997 Cristian Gafton +- obsoletes adduser + +* Thu Oct 23 1997 Cristian Gafton +- modified groupadd; updated the patch + +* Fri Sep 12 1997 Cristian Gafton +- updated to 970616 +- changed useradd to meet RH specs +- fixed some bugs + +* Tue Jun 17 1997 Erik Troan +- built against glibc