summaryrefslogtreecommitdiffstats
path: root/debian/patches
diff options
context:
space:
mode:
Diffstat (limited to 'debian/patches')
-rw-r--r--debian/patches/0001-gpasswd-1-Fix-password-leak.patch137
-rw-r--r--debian/patches/0002-Added-control-character-check.patch45
-rw-r--r--debian/patches/0003-Overhaul-valid_field.patch61
-rw-r--r--debian/patches/008_login_log_failure_in_FTMP51
-rw-r--r--debian/patches/401_cppw_src.dpatch276
-rw-r--r--debian/patches/402_cppw_selinux64
-rw-r--r--debian/patches/429_login_FAILLOG_ENAB84
-rw-r--r--debian/patches/463_login_delay_obeys_to_PAM97
-rw-r--r--debian/patches/501_commonio_group_shadow60
-rw-r--r--debian/patches/502_debian_useradd_defaults41
-rw-r--r--debian/patches/503_shadowconfig.8201
-rw-r--r--debian/patches/505_useradd_recommend_adduser36
-rw-r--r--debian/patches/506_relaxed_usernames111
-rw-r--r--debian/patches/542_useradd-O_option40
-rw-r--r--debian/patches/900_testsuite_groupmems81
-rw-r--r--debian/patches/901_testsuite_gcov76
-rw-r--r--debian/patches/README.patches22
-rw-r--r--debian/patches/series23
18 files changed, 1506 insertions, 0 deletions
diff --git a/debian/patches/0001-gpasswd-1-Fix-password-leak.patch b/debian/patches/0001-gpasswd-1-Fix-password-leak.patch
new file mode 100644
index 0000000..1596b2d
--- /dev/null
+++ b/debian/patches/0001-gpasswd-1-Fix-password-leak.patch
@@ -0,0 +1,137 @@
+From 65c88a43a23c2391dcc90c0abda3e839e9c57904 Mon Sep 17 00:00:00 2001
+From: Alejandro Colomar <alx@kernel.org>
+Date: Sat, 10 Jun 2023 16:20:05 +0200
+Subject: [PATCH] gpasswd(1): Fix password leak
+
+How to trigger this password leak?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When gpasswd(1) asks for the new password, it asks twice (as is usual
+for confirming the new password). Each of those 2 password prompts
+uses agetpass() to get the password. If the second agetpass() fails,
+the first password, which has been copied into the 'static' buffer
+'pass' via STRFCPY(), wasn't being zeroed.
+
+agetpass() is defined in <./libmisc/agetpass.c> (around line 91), and
+can fail for any of the following reasons:
+
+- malloc(3) or readpassphrase(3) failure.
+
+ These are going to be difficult to trigger. Maybe getting the system
+ to the limits of memory utilization at that exact point, so that the
+ next malloc(3) gets ENOMEM, and possibly even the OOM is triggered.
+ About readpassphrase(3), ENFILE and EINTR seem the only plausible
+ ones, and EINTR probably requires privilege or being the same user;
+ but I wouldn't discard ENFILE so easily, if a process starts opening
+ files.
+
+- The password is longer than PASS_MAX.
+
+ The is plausible with physical access. However, at that point, a
+ keylogger will be a much simpler attack.
+
+And, the attacker must be able to know when the second password is being
+introduced, which is not going to be easy.
+
+How to read the password after the leak?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Provoking the leak yourself at the right point by entering a very long
+password is easy, and inspecting the process stack at that point should
+be doable. Try to find some consistent patterns.
+
+Then, search for those patterns in free memory, right after the victim
+leaks their password.
+
+Once you get the leak, a program should read all the free memory
+searching for patterns that gpasswd(1) leaves nearby the leaked
+password.
+
+On 6/10/23 03:14, Seth Arnold wrote:
+> An attacker process wouldn't be able to use malloc(3) for this task.
+> There's a handful of tools available for userspace to allocate memory:
+>
+> - brk / sbrk
+> - mmap MAP_ANONYMOUS
+> - mmap /dev/zero
+> - mmap some other file
+> - shm_open
+> - shmget
+>
+> Most of these return only pages of zeros to a process. Using mmap of an
+> existing file, you can get some of the contents of the file demand-loaded
+> into the memory space on the first use.
+>
+> The MAP_UNINITIALIZED flag only works if the kernel was compiled with
+> CONFIG_MMAP_ALLOW_UNINITIALIZED. This is rare.
+>
+> malloc(3) doesn't zero memory, to our collective frustration, but all the
+> garbage in the allocations is from previous allocations in the current
+> process. It isn't leftover from other processes.
+>
+> The avenues available for reading the memory:
+> - /dev/mem and /dev/kmem (requires root, not available with Secure Boot)
+> - /proc/pid/mem (requires ptrace privileges, mediated by YAMA)
+> - ptrace (requires ptrace privileges, mediated by YAMA)
+> - causing memory to be swapped to disk, and then inspecting the swap
+>
+> These all require a certain amount of privileges.
+
+How to fix it?
+~~~~~~~~~~~~~~
+
+memzero(), which internally calls explicit_bzero(3), or whatever
+alternative the system provides with a slightly different name, will
+make sure that the buffer is zeroed in memory, and optimizations are not
+allowed to impede this zeroing.
+
+This is not really 100% effective, since compilers may place copies of
+the string somewhere hidden in the stack. Those copies won't get zeroed
+by explicit_bzero(3). However, that's arguably a compiler bug, since
+compilers should make everything possible to avoid optimizing strings
+that are later passed to explicit_bzero(3). But we all know that
+sometimes it's impossible to have perfect knowledge in the compiler, so
+this is plausible. Nevertheless, there's nothing we can do against such
+issues, except minimizing the time such passwords are stored in plain
+text.
+
+Security concerns
+~~~~~~~~~~~~~~~~~
+
+We believe this isn't easy to exploit. Nevertheless, and since the fix
+is trivial, this fix should probably be applied soon, and backported to
+all supported distributions, to prevent someone else having more
+imagination than us to find a way.
+
+Affected versions
+~~~~~~~~~~~~~~~~~
+
+All. Bug introduced in shadow 19990709. That's the second commit in
+the git history.
+
+Fixes: 45c6603cc86c ("[svn-upgrade] Integrating new upstream version, shadow (19990709)")
+Reported-by: Alejandro Colomar <alx@kernel.org>
+Cc: Serge Hallyn <serge@hallyn.com>
+Cc: Iker Pedrosa <ipedrosa@redhat.com>
+Cc: Seth Arnold <seth.arnold@canonical.com>
+Cc: Christian Brauner <christian@brauner.io>
+Cc: Balint Reczey <rbalint@debian.org>
+Cc: Sam James <sam@gentoo.org>
+Cc: David Runge <dvzrv@archlinux.org>
+Cc: Andreas Jaeger <aj@suse.de>
+Cc: <~hallyn/shadow@lists.sr.ht>
+Signed-off-by: Alejandro Colomar <alx@kernel.org>
+---
+ src/gpasswd.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/src/gpasswd.c
++++ b/src/gpasswd.c
+@@ -896,6 +896,7 @@
+ strzero (cp);
+ cp = getpass (_("Re-enter new password: "));
+ if (NULL == cp) {
++ memzero (pass, sizeof pass);
+ exit (1);
+ }
+
diff --git a/debian/patches/0002-Added-control-character-check.patch b/debian/patches/0002-Added-control-character-check.patch
new file mode 100644
index 0000000..29adce1
--- /dev/null
+++ b/debian/patches/0002-Added-control-character-check.patch
@@ -0,0 +1,45 @@
+From e5905c4b84d4fb90aefcd96ee618411ebfac663d Mon Sep 17 00:00:00 2001
+From: tomspiderlabs <128755403+tomspiderlabs@users.noreply.github.com>
+Date: Thu, 23 Mar 2023 23:39:38 +0000
+Subject: [PATCH] Added control character check
+
+Added control character check, returning -1 (to "err") if control characters are present.
+---
+ lib/fields.c | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+diff --git a/lib/fields.c b/lib/fields.c
+index 640be931..fb51b582 100644
+--- a/lib/fields.c
++++ b/lib/fields.c
+@@ -21,9 +21,9 @@
+ *
+ * The supplied field is scanned for non-printable and other illegal
+ * characters.
+- * + -1 is returned if an illegal character is present.
+- * + 1 is returned if no illegal characters are present, but the field
+- * contains a non-printable character.
++ * + -1 is returned if an illegal or control character is present.
++ * + 1 is returned if no illegal or control characters are present,
++ * but the field contains a non-printable character.
+ * + 0 is returned otherwise.
+ */
+ int valid_field (const char *field, const char *illegal)
+@@ -45,10 +45,13 @@ int valid_field (const char *field, const char *illegal)
+ }
+
+ if (0 == err) {
+- /* Search if there are some non-printable characters */
++ /* Search if there are non-printable or control characters */
+ for (cp = field; '\0' != *cp; cp++) {
+ if (!isprint (*cp)) {
+ err = 1;
++ }
++ if (!iscntrl (*cp)) {
++ err = -1;
+ break;
+ }
+ }
+--
+2.34.1
+
diff --git a/debian/patches/0003-Overhaul-valid_field.patch b/debian/patches/0003-Overhaul-valid_field.patch
new file mode 100644
index 0000000..b7a8428
--- /dev/null
+++ b/debian/patches/0003-Overhaul-valid_field.patch
@@ -0,0 +1,61 @@
+From 2eaea70111f65b16d55998386e4ceb4273c19eb4 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= <cgzones@googlemail.com>
+Date: Fri, 31 Mar 2023 14:46:50 +0200
+Subject: [PATCH] Overhaul valid_field()
+
+e5905c4b ("Added control character check") introduced checking for
+control characters but had the logic inverted, so it rejects all
+characters that are not control ones.
+
+Cast the character to `unsigned char` before passing to the character
+checking functions to avoid UB.
+
+Use strpbrk(3) for the illegal character test and return early.
+---
+ lib/fields.c | 24 ++++++++++--------------
+ 1 file changed, 10 insertions(+), 14 deletions(-)
+
+diff --git a/lib/fields.c b/lib/fields.c
+index fb51b582..53929248 100644
+--- a/lib/fields.c
++++ b/lib/fields.c
+@@ -37,26 +37,22 @@ int valid_field (const char *field, const char *illegal)
+
+ /* For each character of field, search if it appears in the list
+ * of illegal characters. */
++ if (illegal && NULL != strpbrk (field, illegal)) {
++ return -1;
++ }
++
++ /* Search if there are non-printable or control characters */
+ for (cp = field; '\0' != *cp; cp++) {
+- if (strchr (illegal, *cp) != NULL) {
++ unsigned char c = *cp;
++ if (!isprint (c)) {
++ err = 1;
++ }
++ if (iscntrl (c)) {
+ err = -1;
+ break;
+ }
+ }
+
+- if (0 == err) {
+- /* Search if there are non-printable or control characters */
+- for (cp = field; '\0' != *cp; cp++) {
+- if (!isprint (*cp)) {
+- err = 1;
+- }
+- if (!iscntrl (*cp)) {
+- err = -1;
+- break;
+- }
+- }
+- }
+-
+ return err;
+ }
+
+--
+2.34.1
+
diff --git a/debian/patches/008_login_log_failure_in_FTMP b/debian/patches/008_login_log_failure_in_FTMP
new file mode 100644
index 0000000..0946ca0
--- /dev/null
+++ b/debian/patches/008_login_log_failure_in_FTMP
@@ -0,0 +1,51 @@
+Goal: Log login failures to the btmp file
+
+Notes:
+ * I'm not sure login should add an entry in the FTMP file when PAM is used.
+ (but nothing in /etc/login.defs indicates that the failure is not logged)
+
+--- a/src/login.c
++++ b/src/login.c
+@@ -827,6 +827,24 @@
+ (void) puts ("");
+ (void) puts (_("Login incorrect"));
+
++ if (getdef_str("FTMP_FILE") != NULL) {
++#ifdef USE_UTMPX
++ struct utmpx *failent =
++ prepare_utmpx (failent_user,
++ tty,
++ /* FIXME: or fromhost? */hostname,
++ utent);
++#else /* !USE_UTMPX */
++ struct utmp *failent =
++ prepare_utmp (failent_user,
++ tty,
++ hostname,
++ utent);
++#endif /* !USE_UTMPX */
++ failtmp (failent_user, failent);
++ free (failent);
++ }
++
+ if (failcount >= retries) {
+ SYSLOG ((LOG_NOTICE,
+ "TOO MANY LOGIN TRIES (%u)%s FOR '%s'",
+--- a/lib/getdef.c
++++ b/lib/getdef.c
+@@ -38,7 +38,6 @@
+ {"ENVIRON_FILE", NULL}, \
+ {"ENV_TZ", NULL}, \
+ {"FAILLOG_ENAB", NULL}, \
+- {"FTMP_FILE", NULL}, \
+ {"HMAC_CRYPTO_ALGO", NULL}, \
+ {"ISSUE_FILE", NULL}, \
+ {"LASTLOG_ENAB", NULL}, \
+@@ -80,6 +79,7 @@
+ {"ERASECHAR", NULL},
+ {"FAIL_DELAY", NULL},
+ {"FAKE_SHELL", NULL},
++ {"FTMP_FILE", NULL},
+ {"GID_MAX", NULL},
+ {"GID_MIN", NULL},
+ {"HOME_MODE", NULL},
diff --git a/debian/patches/401_cppw_src.dpatch b/debian/patches/401_cppw_src.dpatch
new file mode 100644
index 0000000..5244702
--- /dev/null
+++ b/debian/patches/401_cppw_src.dpatch
@@ -0,0 +1,276 @@
+#! /bin/sh /usr/share/dpatch/dpatch-run
+## 401_cppw_src.dpatch by Nicolas FRANCOIS <nicolas.francois@centraliens.net>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: Add cppw / cpgr
+
+@DPATCH@
+--- /dev/null
++++ b/src/cppw.c
+@@ -0,0 +1,238 @@
++/*
++ cppw, cpgr copy with locking given file over the password or group file
++ with -s will copy with locking given file over shadow or gshadow file
++
++ Copyright (C) 1999 Stephen Frost <sfrost@snowman.net>
++
++ Based on vipw, vigr by:
++ Copyright (C) 1997 Guy Maor <maor@ece.utexas.edu>
++
++ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++
++ */
++
++#include <config.h>
++#include "defines.h"
++
++#include <errno.h>
++#include <sys/stat.h>
++#include <unistd.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <sys/types.h>
++#include <signal.h>
++#include <utime.h>
++#include "exitcodes.h"
++#include "prototypes.h"
++#include "pwio.h"
++#include "shadowio.h"
++#include "groupio.h"
++#include "sgroupio.h"
++
++
++const char *Prog;
++
++const char *filename, *filenewname;
++static bool filelocked = false;
++static int (*unlock) (void);
++
++/* local function prototypes */
++static int create_copy (FILE *fp, const char *dest, struct stat *sb);
++static void cppwexit (const char *msg, int syserr, int ret);
++static void cppwcopy (const char *file,
++ const char *in_file,
++ int (*file_lock) (void),
++ int (*file_unlock) (void));
++
++static int create_copy (FILE *fp, const char *dest, struct stat *sb)
++{
++ struct utimbuf ub;
++ FILE *bkfp;
++ int c;
++ mode_t mask;
++
++ mask = umask (077);
++ bkfp = fopen (dest, "w");
++ (void) umask (mask);
++ if (NULL == bkfp) {
++ return -1;
++ }
++
++ rewind (fp);
++ while ((c = getc (fp)) != EOF) {
++ if (putc (c, bkfp) == EOF) {
++ break;
++ }
++ }
++
++ if ( (c != EOF)
++ || (fflush (bkfp) != 0)) {
++ (void) fclose (bkfp);
++ (void) unlink (dest);
++ return -1;
++ }
++ if ( (fsync (fileno (bkfp)) != 0)
++ || (fclose (bkfp) != 0)) {
++ (void) unlink (dest);
++ return -1;
++ }
++
++ ub.actime = sb->st_atime;
++ ub.modtime = sb->st_mtime;
++ if ( (utime (dest, &ub) != 0)
++ || (chmod (dest, sb->st_mode) != 0)
++ || (chown (dest, sb->st_uid, sb->st_gid) != 0)) {
++ (void) unlink (dest);
++ return -1;
++ }
++ return 0;
++}
++
++static void cppwexit (const char *msg, int syserr, int ret)
++{
++ int err = errno;
++ if (filelocked) {
++ (*unlock) ();
++ }
++ if (NULL != msg) {
++ fprintf (stderr, "%s: %s", Prog, msg);
++ if (0 != syserr) {
++ fprintf (stderr, ": %s", strerror (err));
++ }
++ (void) fputs ("\n", stderr);
++ }
++ if (NULL != filename) {
++ fprintf (stderr, _("%s: %s is unchanged\n"), Prog, filename);
++ } else {
++ fprintf (stderr, _("%s: no changes\n"), Prog);
++ }
++
++ exit (ret);
++}
++
++static void cppwcopy (const char *file,
++ const char *in_file,
++ int (*file_lock) (void),
++ int (*file_unlock) (void))
++{
++ struct stat st1;
++ FILE *f;
++ char filenew[1024];
++
++ snprintf (filenew, sizeof filenew, "%s.new", file);
++ unlock = file_unlock;
++ filename = file;
++ filenewname = filenew;
++
++ if (access (file, F_OK) != 0) {
++ cppwexit (file, 1, 1);
++ }
++ if (file_lock () == 0) {
++ cppwexit (_("Couldn't lock file"), 0, 5);
++ }
++ filelocked = true;
++
++ /* file to copy has same owners, perm */
++ if (stat (file, &st1) != 0) {
++ cppwexit (file, 1, 1);
++ }
++ f = fopen (in_file, "r");
++ if (NULL == f) {
++ cppwexit (in_file, 1, 1);
++ }
++ if (create_copy (f, filenew, &st1) != 0) {
++ cppwexit (_("Couldn't make copy"), errno, 1);
++ }
++
++ /* XXX - here we should check filenew for errors; if there are any,
++ * fail w/ an appropriate error code and let the user manually fix
++ * it. Use pwck or grpck to do the check. - Stephen (Shamelessly
++ * stolen from '--marekm's comment) */
++
++ if (rename (filenew, file) != 0) {
++ fprintf (stderr, _("%s: can't copy %s: %s)\n"),
++ Prog, filenew, strerror (errno));
++ cppwexit (NULL,0,1);
++ }
++
++ (*file_unlock) ();
++}
++
++int main (int argc, char **argv)
++{
++ int flag;
++ bool cpshadow = false;
++ char *in_file;
++ int e = E_USAGE;
++ bool do_cppw = true;
++
++ (void) setlocale (LC_ALL, "");
++ (void) bindtextdomain (PACKAGE, LOCALEDIR);
++ (void) textdomain (PACKAGE);
++
++ Prog = Basename (argv[0]);
++ if (strcmp (Prog, "cpgr") == 0) {
++ do_cppw = false;
++ }
++
++ while ((flag = getopt (argc, argv, "ghps")) != EOF) {
++ switch (flag) {
++ case 'p':
++ do_cppw = true;
++ break;
++ case 'g':
++ do_cppw = false;
++ break;
++ case 's':
++ cpshadow = true;
++ break;
++ case 'h':
++ e = E_SUCCESS;
++ /*pass through*/
++ default:
++ (void) fputs (_("Usage:\n\
++`cppw <file>' copys over /etc/passwd `cppw -s <file>' copys over /etc/shadow\n\
++`cpgr <file>' copys over /etc/group `cpgr -s <file>' copys over /etc/gshadow\n\
++"), (E_SUCCESS != e) ? stderr : stdout);
++ exit (e);
++ }
++ }
++
++ if (argc != optind + 1) {
++ cppwexit (_("wrong number of arguments, -h for usage"),0,1);
++ }
++
++ in_file = argv[optind];
++
++ if (do_cppw) {
++ if (cpshadow) {
++ cppwcopy (SHADOW_FILE, in_file, spw_lock, spw_unlock);
++ } else {
++ cppwcopy (PASSWD_FILE, in_file, pw_lock, pw_unlock);
++ }
++ } else {
++#ifdef SHADOWGRP
++ if (cpshadow) {
++ cppwcopy (SGROUP_FILE, in_file, sgr_lock, sgr_unlock);
++ } else
++#endif /* SHADOWGRP */
++ {
++ cppwcopy (GROUP_FILE, in_file, gr_lock, gr_unlock);
++ }
++ }
++
++ return 0;
++}
++
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -34,6 +34,7 @@
+ bin_PROGRAMS += su
+ endif
+ usbin_PROGRAMS = \
++ cppw \
+ chgpasswd \
+ chpasswd \
+ groupadd \
+@@ -102,6 +103,7 @@
+ chgpasswd_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) $(LIBCRYPT) $(LIBECONF)
+ chsh_LDADD = $(LDADD) $(LIBPAM) $(LIBAUDIT) $(LIBSELINUX) $(LIBCRYPT_NOPAM) $(LIBSKEY) $(LIBMD) $(LIBECONF)
+ chpasswd_LDADD = $(LDADD) $(LIBPAM) $(LIBAUDIT) $(LIBSELINUX) $(LIBCRYPT) $(LIBECONF)
++cppw_LDADD = $(LDADD) $(LIBSELINUX) $(LIBAUDIT)
+ expiry_LDADD = $(LDADD) $(LIBECONF)
+ gpasswd_LDADD = $(LDADD) $(LIBAUDIT) $(LIBSELINUX) $(LIBCRYPT) $(LIBECONF)
+ groupadd_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) $(LIBECONF) -ldl
+--- a/po/POTFILES.in
++++ b/po/POTFILES.in
+@@ -91,6 +91,7 @@
+ src/chgpasswd.c
+ src/chpasswd.c
+ src/chsh.c
++src/cppw.c
+ src/expiry.c
+ src/faillog.c
+ src/gpasswd.c
diff --git a/debian/patches/402_cppw_selinux b/debian/patches/402_cppw_selinux
new file mode 100644
index 0000000..5f2da1b
--- /dev/null
+++ b/debian/patches/402_cppw_selinux
@@ -0,0 +1,64 @@
+Goal: Add selinux support to cppw
+
+Fix:
+
+Status wrt upstream: cppw is not available upstream.
+ The patch was made based on the
+ 302_vim_selinux_support patch. It needs to be
+ reviewed by an SE-Linux aware person.
+
+Depends on 401_cppw_src.dpatch
+
+Index: git/src/cppw.c
+===================================================================
+--- git.orig/src/cppw.c
++++ git/src/cppw.c
+@@ -34,6 +34,9 @@
+ #include <sys/types.h>
+ #include <signal.h>
+ #include <utime.h>
++#ifdef WITH_SELINUX
++#include <selinux/selinux.h>
++#endif /* WITH_SELINUX */
+ #include "exitcodes.h"
+ #include "prototypes.h"
+ #include "pwio.h"
+@@ -139,6 +142,22 @@
+ if (access (file, F_OK) != 0) {
+ cppwexit (file, 1, 1);
+ }
++#ifdef WITH_SELINUX
++ /* if SE Linux is enabled then set the context of all new files
++ * to be the context of the file we are editing */
++ if (is_selinux_enabled () > 0) {
++ security_context_t passwd_context=NULL;
++ int ret = 0;
++ if (getfilecon (file, &passwd_context) < 0) {
++ cppwexit (_("Couldn't get file context"), errno, 1);
++ }
++ ret = setfscreatecon (passwd_context);
++ freecon (passwd_context);
++ if (0 != ret) {
++ cppwexit (_("setfscreatecon () failed"), errno, 1);
++ }
++ }
++#endif /* WITH_SELINUX */
+ if (file_lock () == 0) {
+ cppwexit (_("Couldn't lock file"), 0, 5);
+ }
+@@ -167,6 +186,15 @@
+ cppwexit (NULL,0,1);
+ }
+
++#ifdef WITH_SELINUX
++ /* unset the fscreatecon */
++ if (is_selinux_enabled () > 0) {
++ if (setfscreatecon (NULL)) {
++ cppwexit (_("setfscreatecon() failed"), errno, 1);
++ }
++ }
++#endif /* WITH_SELINUX */
++
+ (*file_unlock) ();
+ }
+
diff --git a/debian/patches/429_login_FAILLOG_ENAB b/debian/patches/429_login_FAILLOG_ENAB
new file mode 100644
index 0000000..d8e6034
--- /dev/null
+++ b/debian/patches/429_login_FAILLOG_ENAB
@@ -0,0 +1,84 @@
+Goal: Re-enable logging and displaying failures on login when login is
+ compiled with PAM and when FAILLOG_ENAB is set to yes. And create the
+ faillog file if it does not exist on postinst (as on Woody).
+Depends: 008_login_more_LOG_UNKFAIL_ENAB
+Fixes: #192849
+
+Note: It could be removed if pam_tally could report the number of failures
+ preceding a successful login.
+
+--- a/src/login.c
++++ b/src/login.c
+@@ -114,9 +114,9 @@
+ #endif
+ );
+
+-#ifndef USE_PAM
+ static struct faillog faillog;
+
++#ifndef USE_PAM
+ static void bad_time_notify (void);
+ static void check_nologin (bool login_to_root);
+ #else
+@@ -787,6 +787,9 @@
+ SYSLOG ((LOG_NOTICE,
+ "TOO MANY LOGIN TRIES (%u)%s FOR '%s'",
+ failcount, fromhost, failent_user));
++ if ((NULL != pwd) && getdef_bool("FAILLOG_ENAB")) {
++ failure (pwd->pw_uid, tty, &faillog);
++ }
+ fprintf (stderr,
+ _("Maximum number of tries exceeded (%u)\n"),
+ failcount);
+@@ -804,6 +807,14 @@
+ pam_strerror (pamh, retcode)));
+ failed = true;
+ }
++ if ( (NULL != pwd)
++ && getdef_bool("FAILLOG_ENAB")
++ && ! failcheck (pwd->pw_uid, &faillog, failed)) {
++ SYSLOG((LOG_CRIT,
++ "exceeded failure limit for `%s' %s",
++ failent_user, fromhost));
++ failed = 1;
++ }
+
+ if (!failed) {
+ break;
+@@ -827,6 +838,10 @@
+ (void) puts ("");
+ (void) puts (_("Login incorrect"));
+
++ if ((NULL != pwd) && getdef_bool("FAILLOG_ENAB")) {
++ failure (pwd->pw_uid, tty, &faillog);
++ }
++
+ if (getdef_str("FTMP_FILE") != NULL) {
+ #ifdef USE_UTMPX
+ struct utmpx *failent =
+@@ -1295,6 +1310,7 @@
+ */
+ #ifndef USE_PAM
+ motd (); /* print the message of the day */
++#endif
+ if ( getdef_bool ("FAILLOG_ENAB")
+ && (0 != faillog.fail_cnt)) {
+ failprint (&faillog);
+@@ -1307,6 +1323,7 @@
+ username, (int) faillog.fail_cnt));
+ }
+ }
++#ifndef USE_PAM
+ if ( getdef_bool ("LASTLOG_ENAB")
+ && pwd->pw_uid <= (uid_t) getdef_ulong ("LASTLOG_UID_MAX", 0xFFFFFFFFUL)
+ && (ll.ll_time != 0)) {
+--- a/lib/getdef.c
++++ b/lib/getdef.c
+@@ -78,6 +78,7 @@
+ {"ENV_SUPATH", NULL},
+ {"ERASECHAR", NULL},
+ {"FAIL_DELAY", NULL},
++ {"FAILLOG_ENAB", NULL},
+ {"FAKE_SHELL", NULL},
+ {"FTMP_FILE", NULL},
+ {"GID_MAX", NULL},
diff --git a/debian/patches/463_login_delay_obeys_to_PAM b/debian/patches/463_login_delay_obeys_to_PAM
new file mode 100644
index 0000000..ab32c2a
--- /dev/null
+++ b/debian/patches/463_login_delay_obeys_to_PAM
@@ -0,0 +1,97 @@
+Goal: Do not hardcode pam_fail_delay and let pam_unix do its
+ job to set a delay...or not
+
+Fixes: #87648
+
+Status wrt upstream: Forwarded but not applied yet
+
+Note: If removed, FAIL_DELAY must be re-added to /etc/login.defs
+
+--- a/src/login.c
++++ b/src/login.c
+@@ -512,7 +512,6 @@
+ #if !defined(USE_PAM)
+ char ptime[80];
+ #endif
+- unsigned int delay;
+ unsigned int retries;
+ bool subroot = false;
+ #ifndef USE_PAM
+@@ -537,6 +536,7 @@
+ pid_t child;
+ char *pam_user = NULL;
+ #else
++ unsigned int delay;
+ struct spwd *spwd = NULL;
+ #endif
+ /*
+@@ -701,7 +701,6 @@
+ }
+
+ environ = newenvp; /* make new environment active */
+- delay = getdef_unum ("FAIL_DELAY", 1);
+ retries = getdef_unum ("LOGIN_RETRIES", RETRIES);
+
+ #ifdef USE_PAM
+@@ -717,8 +716,7 @@
+
+ /*
+ * hostname & tty are either set to NULL or their correct values,
+- * depending on how much we know. We also set PAM's fail delay to
+- * ours.
++ * depending on how much we know.
+ *
+ * PAM_RHOST and PAM_TTY are used for authentication, only use
+ * information coming from login or from the caller (e.g. no utmp)
+@@ -727,10 +725,6 @@
+ PAM_FAIL_CHECK;
+ retcode = pam_set_item (pamh, PAM_TTY, tty);
+ PAM_FAIL_CHECK;
+-#ifdef HAS_PAM_FAIL_DELAY
+- retcode = pam_fail_delay (pamh, 1000000 * delay);
+- PAM_FAIL_CHECK;
+-#endif
+ /* if fflg, then the user has already been authenticated */
+ if (!fflg) {
+ unsigned int failcount = 0;
+@@ -771,12 +765,6 @@
+ bool failed = false;
+
+ failcount++;
+-#ifdef HAS_PAM_FAIL_DELAY
+- if (delay > 0) {
+- retcode = pam_fail_delay(pamh, 1000000*delay);
+- PAM_FAIL_CHECK;
+- }
+-#endif
+
+ retcode = pam_authenticate (pamh, 0);
+
+@@ -1110,14 +1098,17 @@
+ free (username);
+ username = NULL;
+
++#ifndef USE_PAM
+ /*
+ * Wait a while (a la SVR4 /usr/bin/login) before attempting
+ * to login the user again. If the earlier alarm occurs
+ * before the sleep() below completes, login will exit.
+ */
++ delay = getdef_unum ("FAIL_DELAY", 1);
+ if (delay > 0) {
+ (void) sleep (delay);
+ }
++#endif
+
+ (void) puts (_("Login incorrect"));
+
+--- a/lib/getdef.c
++++ b/lib/getdef.c
+@@ -77,7 +77,6 @@
+ {"ENV_PATH", NULL},
+ {"ENV_SUPATH", NULL},
+ {"ERASECHAR", NULL},
+- {"FAIL_DELAY", NULL},
+ {"FAILLOG_ENAB", NULL},
+ {"FAKE_SHELL", NULL},
+ {"FTMP_FILE", NULL},
diff --git a/debian/patches/501_commonio_group_shadow b/debian/patches/501_commonio_group_shadow
new file mode 100644
index 0000000..cfdf10c
--- /dev/null
+++ b/debian/patches/501_commonio_group_shadow
@@ -0,0 +1,60 @@
+Goal: save the [g]shadow files with the 'shadow' group and mode 0440
+
+Fixes: #166793
+
+--- a/lib/commonio.c
++++ b/lib/commonio.c
+@@ -21,6 +21,7 @@
+ #include <errno.h>
+ #include <stdio.h>
+ #include <signal.h>
++#include <grp.h>
+ #include "nscd.h"
+ #include "sssd.h"
+ #ifdef WITH_TCB
+@@ -970,12 +971,23 @@
+ goto fail;
+ }
+ } else {
++ struct group *grp;
+ /*
+ * Default permissions for new [g]shadow files.
+ */
+ sb.st_mode = db->st_mode;
+ sb.st_uid = db->st_uid;
+ sb.st_gid = db->st_gid;
++
++ /*
++ * Try to retrieve the shadow's GID, and fall back to GID 0.
++ */
++ if (sb.st_gid == 0) {
++ if ((grp = getgrnam("shadow")) != NULL)
++ sb.st_gid = grp->gr_gid;
++ else
++ sb.st_gid = 0;
++ }
+ }
+
+ snprintf (buf, sizeof buf, "%s+", db->filename);
+--- a/lib/sgroupio.c
++++ b/lib/sgroupio.c
+@@ -206,7 +206,7 @@
+ #ifdef WITH_SELINUX
+ NULL, /* scontext */
+ #endif
+- 0400, /* st_mode */
++ 0440, /* st_mode */
+ 0, /* st_uid */
+ 0, /* st_gid */
+ NULL, /* head */
+--- a/lib/shadowio.c
++++ b/lib/shadowio.c
+@@ -84,7 +84,7 @@
+ #ifdef WITH_SELINUX
+ NULL, /* scontext */
+ #endif /* WITH_SELINUX */
+- 0400, /* st_mode */
++ 0440, /* st_mode */
+ 0, /* st_uid */
+ 0, /* st_gid */
+ NULL, /* head */
diff --git a/debian/patches/502_debian_useradd_defaults b/debian/patches/502_debian_useradd_defaults
new file mode 100644
index 0000000..6317ed6
--- /dev/null
+++ b/debian/patches/502_debian_useradd_defaults
@@ -0,0 +1,41 @@
+From: Balint Reczey <balint@balintreczey.hu>
+Description: Keep using Debian's adduser defaults
+ Upstream's bbf4b79bc49fd1826eb41f6629669ef0b647267b commit
+ in 4.9 merged those values from upstream's default configuration file
+ which is not shipped in Debian.
+ This patch keeps the program's compiled in defaults in sync with the
+ configuration files shipped in Debian (debian/default/useradd).
+Bug: https://github.com/shadow-maint/shadow/issues/501
+Bug-Debian: https://bugs.debian.org/1004710
+Forwarded: not-needed
+
+--- a/src/useradd.c
++++ b/src/useradd.c
+@@ -79,12 +79,12 @@
+ /*
+ * These defaults are used if there is no defaults file.
+ */
+-static gid_t def_group = 1000;
++static gid_t def_group = 100;
+ static const char *def_gname = "other";
+ static const char *def_home = "/home";
+ static const char *def_shell = "/bin/bash";
+ static const char *def_template = SKEL_DIR;
+-static const char *def_create_mail_spool = "yes";
++static const char *def_create_mail_spool = "no";
+ static const char *def_log_init = "yes";
+
+ static long def_inactive = -1;
+diff --git a/man/useradd.8.xml b/man/useradd.8.xml
+index af02a23f..c7f95b47 100644
+--- a/man/useradd.8.xml
++++ b/man/useradd.8.xml
+@@ -248,7 +248,7 @@
+ command line), useradd will set the primary group of the new
+ user to the value specified by the <option>GROUP</option>
+ variable in <filename>/etc/default/useradd</filename>, or
+- 1000 by default.
++ 100 by default.
+ </para>
+ </listitem>
+ </varlistentry>
diff --git a/debian/patches/503_shadowconfig.8 b/debian/patches/503_shadowconfig.8
new file mode 100644
index 0000000..0f0d339
--- /dev/null
+++ b/debian/patches/503_shadowconfig.8
@@ -0,0 +1,201 @@
+Goal: Document the shadowconfig utility
+
+Status wrt upstream: The shadowconfig utility is debian specific.
+ Its man page also (but it used to be distributed)
+
+Index: git/man/shadowconfig.8
+===================================================================
+--- /dev/null
++++ git/man/shadowconfig.8
+@@ -0,0 +1,41 @@
++.\"Generated by db2man.xsl. Don't modify this, modify the source.
++.de Sh \" Subsection
++.br
++.if t .Sp
++.ne 5
++.PP
++\fB\\$1\fR
++.PP
++..
++.de Sp \" Vertical space (when we can't use .PP)
++.if t .sp .5v
++.if n .sp
++..
++.de Ip \" List item
++.br
++.ie \\n(.$>=3 .ne \\$3
++.el .ne 3
++.IP "\\$1" \\$2
++..
++.TH "SHADOWCONFIG" 8 "19 Apr 1997" "" ""
++.SH NAME
++shadowconfig \- toggle shadow passwords on and off
++.SH "SYNOPSIS"
++.ad l
++.hy 0
++.HP 13
++\fBshadowconfig\fR \fB\fIon\fR\fR | \fB\fIoff\fR\fR
++.ad
++.hy
++
++.SH "DESCRIPTION"
++
++.PP
++\fBshadowconfig\fR on will turn shadow passwords on; \fIshadowconfig off\fR will turn shadow passwords off\&. \fBshadowconfig\fR will print an error message and exit with a nonzero code if it finds anything awry\&. If that happens, you should correct the error and run it again\&. Turning shadow passwords on when they are already on, or off when they are already off, is harmless\&.
++
++.PP
++Read \fI/usr/share/doc/passwd/README\&.Debian\fR for a brief introduction to shadow passwords and related features\&.
++
++.PP
++Note that turning shadow passwords off and on again will lose all password aging information\&.
++
+Index: git/man/shadowconfig.8.xml
+===================================================================
+--- /dev/null
++++ git/man/shadowconfig.8.xml
+@@ -0,0 +1,52 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
++ "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd">
++<refentry id='shadowconfig.8'>
++ <!-- $Id: shadowconfig.8.xml,v 1.6 2005/06/15 12:39:27 kloczek Exp $ -->
++ <refentryinfo>
++ <date>19 Apr 1997</date>
++ </refentryinfo>
++ <refmeta>
++ <refentrytitle>shadowconfig</refentrytitle>
++ <manvolnum>8</manvolnum>
++ <refmiscinfo class='date'>19 Apr 1997</refmiscinfo>
++ <refmiscinfo class='source'>Debian GNU/Linux</refmiscinfo>
++ </refmeta>
++ <refnamediv id='name'>
++ <refname>shadowconfig</refname>
++ <refpurpose>toggle shadow passwords on and off</refpurpose>
++ </refnamediv>
++
++ <refsynopsisdiv id='synopsis'>
++ <cmdsynopsis>
++ <command>shadowconfig</command>
++ <group choice='plain'>
++ <arg choice='plain'><replaceable>on</replaceable></arg>
++ <arg choice='plain'><replaceable>off</replaceable></arg>
++ </group>
++ </cmdsynopsis>
++ </refsynopsisdiv>
++
++ <refsect1 id='description'>
++ <title>DESCRIPTION</title>
++ <para><command>shadowconfig</command> on will turn shadow passwords on;
++ <emphasis remap='B'>shadowconfig off</emphasis> will turn shadow
++ passwords off. <command>shadowconfig</command> will print an error
++ message and exit with a nonzero code if it finds anything awry. If
++ that happens, you should correct the error and run it again. Turning
++ shadow passwords on when they are already on, or off when they are
++ already off, is harmless.
++ </para>
++
++ <para>
++ Read <filename>/usr/share/doc/passwd/README.Debian</filename> for a
++ brief introduction
++ to shadow passwords and related features.
++ </para>
++
++ <para>Note that turning shadow passwords off and on again will lose all
++ password
++ aging information.
++ </para>
++ </refsect1>
++</refentry>
+Index: git/man/fr/shadowconfig.8
+===================================================================
+--- /dev/null
++++ git/man/fr/shadowconfig.8
+@@ -0,0 +1,26 @@
++.\" This file was generated with po4a. Translate the source file.
++.\"
++.\"$Id: shadowconfig.8,v 1.4 2001/08/23 23:10:48 kloczek Exp $
++.TH SHADOWCONFIG 8 "19 avril 1997" "Debian GNU/Linux"
++.SH NOM
++shadowconfig \- active ou désactive les mots de passe cachés
++.SH SYNOPSIS
++\fBshadowconfig\fP \fIon\fP | \fIoff\fP
++.SH DESCRIPTION
++.PP
++\fBshadowconfig on\fP active les mots de passe cachés («\ shadow passwords\ »)\ ; \fBshadowconfig off\fP les désactive. \fBShadowconfig\fP affiche un message
++d'erreur et quitte avec une valeur de retour non nulle s'il rencontre
++quelque chose d'inattendu. Dans ce cas, vous devrez corriger l'erreur avant
++de recommencer.
++
++Activer les mots de passe cachés lorsqu'ils sont déjà activés, ou les
++désactiver lorsqu'ils ne sont pas actifs est sans effet.
++
++Lisez \fI/usr/share/doc/passwd/README.Debian\fP pour une brève introduction aux
++mots de passe cachés et à leurs fonctionnalités.
++
++Notez que désactiver puis réactiver les mots de passe cachés aura pour
++conséquence la perte des informations d'âge sur les mots de passe.
++.SH TRADUCTION
++Nicolas FRANÇOIS, 2004.
++Veuillez signaler toute erreur à <\fIdebian\-l10\-french@lists.debian.org\fR>.
+Index: git/man/ja/shadowconfig.8
+===================================================================
+--- /dev/null
++++ git/man/ja/shadowconfig.8
+@@ -0,0 +1,25 @@
++.\" all right reserved,
++.\" Translated Tue Oct 30 11:59:11 JST 2001
++.\" by Maki KURODA <mkuroda@aisys-jp.com>
++.\"
++.TH SHADOWCONFIG 8 "19 Apr 1997" "Debian GNU/Linux"
++.SH 名前
++shadowconfig \- shadow パスワードの設定をオン及びオフに切替える
++.SH 書式
++.B "shadowconfig"
++.IR on " | " off
++.SH 説明
++.PP
++.B shadowconfig on
++は shadow パスワードを有効にする。
++.B shadowconfig off
++は shadow パスワードを無効にする。
++.B shadowconfig
++は何らかの間違いがあると、エラーメッセージを表示し、
++ゼロではない返り値を返す。
++もしそのようなことが起こった場合、エラーを修正し、再度実行しなければならない。
++shadow パスワードの設定がすでにオンの場合にオンに設定したり、
++すでにオフの場合にオフに設定しても、何の影響もない。
++
++.I /usr/share/doc/passwd/README.debian.gz
++には shadow パスワードとそれに関する特徴の簡単な紹介が書かれている。
+Index: git/man/pl/shadowconfig.8
+===================================================================
+--- /dev/null
++++ git/man/pl/shadowconfig.8
+@@ -0,0 +1,27 @@
++.\" $Id: shadowconfig.8,v 1.3 2001/08/23 23:10:51 kloczek Exp $
++.\" {PTM/WK/1999-09-14}
++.TH SHADOWCONFIG 8 "19 kwietnia 1997" "Debian GNU/Linux"
++.SH NAZWA
++shadowconfig - przełącza ochronę haseł i grup przez pliki shadow
++.SH SKŁADNIA
++.B "shadowconfig"
++.IR on " | " off
++.SH OPIS
++.PP
++.B shadowconfig on
++włącza ochronę haseł i grup przez dodatkowe, przesłaniane pliki (shadow);
++.B shadowconfig off
++wyłącza dodatkowe pliki haseł i grup.
++.B shadowconfig
++wyświetla komunikat o błędzie i kończy pracę z niezerowym kodem jeśli
++znajdzie coś nieprawidłowego. W takim wypadku powinieneś poprawić błąd
++.\" if it finds anything awry.
++i uruchomić program ponownie.
++
++Włączenie ochrony haseł, gdy jest ona już włączona lub jej wyłączenie,
++gdy jest wyłączona jest nieszkodliwe.
++
++Przeczytaj
++.IR /usr/share/doc/passwd/README.debian.gz ,
++gdzie znajdziesz krótkie wprowadzenie do ochrony haseł z użyciem dodatkowych
++plików haseł przesłanianych (shadow passwords) i związanych tematów.
diff --git a/debian/patches/505_useradd_recommend_adduser b/debian/patches/505_useradd_recommend_adduser
new file mode 100644
index 0000000..9fb3fe3
--- /dev/null
+++ b/debian/patches/505_useradd_recommend_adduser
@@ -0,0 +1,36 @@
+Goal: Recommend using adduser and deluser.
+
+Fixes: #406046
+
+Status wrt upstream: Debian specific patch.
+
+--- a/man/useradd.8.xml
++++ b/man/useradd.8.xml
+@@ -83,6 +83,12 @@
+ <refsect1 id='description'>
+ <title>DESCRIPTION</title>
+ <para>
++ <command>useradd</command> is a low level utility for adding
++ users. On Debian, administrators should usually use
++ <citerefentry><refentrytitle>adduser</refentrytitle>
++ <manvolnum>8</manvolnum></citerefentry> instead.
++ </para>
++ <para>
+ When invoked without the <option>-D</option> option, the
+ <command>useradd</command> command creates a new user account using
+ the values specified on the command line plus the default values from
+--- a/man/userdel.8.xml
++++ b/man/userdel.8.xml
+@@ -59,6 +59,12 @@
+ <refsect1 id='description'>
+ <title>DESCRIPTION</title>
+ <para>
++ <command>userdel</command> is a low level utility for removing
++ users. On Debian, administrators should usually use
++ <citerefentry><refentrytitle>deluser</refentrytitle>
++ <manvolnum>8</manvolnum></citerefentry> instead.
++ </para>
++ <para>
+ The <command>userdel</command> command modifies the system account
+ files, deleting all entries that refer to the user name <emphasis
+ remap='I'>LOGIN</emphasis>. The named user must exist.
diff --git a/debian/patches/506_relaxed_usernames b/debian/patches/506_relaxed_usernames
new file mode 100644
index 0000000..0e066d9
--- /dev/null
+++ b/debian/patches/506_relaxed_usernames
@@ -0,0 +1,111 @@
+Goal: Relaxed usernames/groupnames checking patch.
+
+Status wrt upstream: Debian specific. Not to be used upstream
+
+Details:
+ Allows any non-empty user/grounames that don't contain ':', ',' or '\n'
+ characters and don't start with '-', '+', or '~'. This patch is more
+ restrictive than original Karl's version. closes: #264879
+ Also closes: #377844
+
+ Comments from Karl Ramm (shadow 1:4.0.3-9, 20 Aug 2003 02:06:50 -0400):
+
+ I can't come up with a good justification as to why characters other
+ than ':'s and '\0's should be disallowed in group and usernames (other
+ than '-' as the leading character). Thus, the maintenance tools don't
+ anymore. closes: #79682, #166798, #171179
+
+--- a/libmisc/chkname.c
++++ b/libmisc/chkname.c
+@@ -32,44 +32,26 @@
+ }
+
+ /*
+- * 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 == '.')) {
++ * POSIX indicate that usernames are composed of characters from the
++ * portable filename character set [A-Za-z0-9._-], and that the hyphen
++ * should not be used as the first character of a portable user name.
++ *
++ * Allow more relaxed user/group names in Debian -- ^[^-~+:,\s][^:,\s]*$
++ */
++ if ( ('\0' == *name)
++ || ('-' == *name)
++ || ('~' == *name)
++ || ('+' == *name)) {
+ return false;
+ }
+-
+- numeric = isdigit(*name);
+-
+- while ('\0' != *++name) {
+- if (!((*name >= 'a' && *name <= 'z') ||
+- (*name >= 'A' && *name <= 'Z') ||
+- (*name >= '0' && *name <= '9') ||
+- *name == '_' ||
+- *name == '.' ||
+- *name == '-' ||
+- (*name == '$' && name[1] == '\0')
+- )) {
++ do {
++ if ((':' == *name) || (',' == *name) || isspace(*name)) {
+ return false;
+ }
+- numeric &= isdigit(*name);
+- }
++ name++;
++ } while ('\0' != *name);
+
+- return !numeric;
++ return true;
+ }
+
+ bool is_valid_user_name (const char *name)
+--- a/man/useradd.8.xml
++++ b/man/useradd.8.xml
+@@ -708,6 +708,14 @@
+ the <command>ls</command> output.
+ </para>
+ <para>
++ On Debian, the only constraints are that usernames must neither start
++ with a dash ('-') nor plus ('+') nor tilde ('~') nor contain a
++ colon (':'), a comma (','), or a whitespace (space: ' ',
++ end of line: '\n', tabulation: '\t', etc.). Note that using a slash
++ ('/') may break the default algorithm for the definition of the
++ user's home directory.
++ </para>
++ <para>
+ Usernames may only be up to 32 characters long.
+ </para>
+ </refsect1>
+--- a/man/groupadd.8.xml
++++ b/man/groupadd.8.xml
+@@ -72,6 +72,12 @@
+ also disallowed.
+ </para>
+ <para>
++ On Debian, the only constraints are that groupnames must neither start
++ with a dash ('-') nor plus ('+') nor tilde ('~') nor contain a
++ colon (':'), a comma (','), or a whitespace (space:' ',
++ end of line: '\n', tabulation: '\t', etc.).
++ </para>
++ <para>
+ Groupnames may only be up to &GROUP_NAME_MAX_LENGTH; characters long.
+ </para>
+ </refsect1>
diff --git a/debian/patches/542_useradd-O_option b/debian/patches/542_useradd-O_option
new file mode 100644
index 0000000..3745826
--- /dev/null
+++ b/debian/patches/542_useradd-O_option
@@ -0,0 +1,40 @@
+Goal: accepts the -O flag for backward compatibility. (was used by adduser?)
+
+Note: useradd.8 needs to be regenerated.
+
+Status wrt upstream: not included as this is just specific
+ backward compatibility for Debian
+
+--- a/man/useradd.8.xml
++++ b/man/useradd.8.xml
+@@ -326,6 +326,11 @@
+ =<replaceable>100</replaceable>&nbsp;<option>-K</option>&nbsp;
+ <replaceable>UID_MAX</replaceable>=<replaceable>499</replaceable>
+ </para>
++ <para>
++ For the compatibility with previous Debian's
++ <command>useradd</command>, the <option>-O</option> option is
++ also supported.
++ </para>
+ <!--para>
+ Note: <option>-K</option>&nbsp;<replaceable>UID_MIN</replaceable>=<replaceable>10</replaceable>,<replaceable>UID_MAX</replaceable>=<replaceable>499</replaceable>
+ doesn't work yet.
+--- a/src/useradd.c
++++ b/src/useradd.c
+@@ -1227,7 +1227,7 @@
+ {NULL, 0, NULL, '\0'}
+ };
+ while ((c = getopt_long (argc, argv,
+- "b:c:d:De:f:g:G:hk:K:lmMNop:rR:P:s:u:U"
++ "b:c:d:De:f:g:G:hk:O:K:lmMNop:rR:P:s:u:U"
+ #ifdef WITH_SELINUX
+ "Z:"
+ #endif /* WITH_SELINUX */
+@@ -1367,6 +1367,7 @@
+ kflg = true;
+ break;
+ case 'K':
++ case 'O': /* compatibility with previous Debian useradd */
+ /*
+ * override login.defs defaults (-K name=value)
+ * example: -K UID_MIN=100 -K UID_MAX=499
diff --git a/debian/patches/900_testsuite_groupmems b/debian/patches/900_testsuite_groupmems
new file mode 100644
index 0000000..6bdc497
--- /dev/null
+++ b/debian/patches/900_testsuite_groupmems
@@ -0,0 +1,81 @@
+--- a/debian/passwd.install
++++ b/debian/passwd.install
+@@ -9,6 +9,7 @@
+ usr/sbin/cppw
+ usr/sbin/groupadd
+ usr/sbin/groupdel
++usr/sbin/groupmems
+ usr/sbin/groupmod
+ usr/sbin/grpck
+ usr/sbin/grpconv
+@@ -33,6 +34,7 @@
+ usr/share/man/*/man8/chpasswd.8
+ usr/share/man/*/man8/groupadd.8
+ usr/share/man/*/man8/groupdel.8
++usr/share/man/*/man8/groupmems.8
+ usr/share/man/*/man8/groupmod.8
+ usr/share/man/*/man8/grpck.8
+ usr/share/man/*/man8/grpconv.8
+@@ -59,6 +61,7 @@
+ usr/share/man/man8/chpasswd.8
+ usr/share/man/man8/groupadd.8
+ usr/share/man/man8/groupdel.8
++usr/share/man/man8/groupmems.8
+ usr/share/man/man8/groupmod.8
+ usr/share/man/man8/grpck.8
+ usr/share/man/man8/grpconv.8
+--- a/debian/passwd.postinst
++++ b/debian/passwd.postinst
+@@ -31,6 +31,24 @@
+ exit 1
+ )
+ fi
++ if ! getent group groupmems | grep -q '^groupmems:[^:]*:99'
++ then
++ groupadd -g 99 groupmems || (
++ cat <<EOF
++************************ TESTSUITE *****************************
++Group ID 99 has been allocated for the groupmems group. You have either
++used 99 yourself or created a groupmems group with a different ID.
++Please correct this problem and reconfigure with ``dpkg --configure passwd''.
++
++Note that both user and group IDs in the range 0-99 are globally
++allocated by the Debian project and must be the same on every Debian
++system.
++EOF
++ exit 1
++ )
++# FIXME
++ chgrp groupmems /usr/sbin/groupmems
++ fi
+ ;;
+ esac
+
+--- a/debian/rules
++++ b/debian/rules
+@@ -60,6 +60,7 @@
+ dh_installpam -p passwd --name=chsh
+ dh_installpam -p passwd --name=chpasswd
+ dh_installpam -p passwd --name=newusers
++ dh_installpam -p passwd --name=groupmems
+ ifeq ($(DEB_HOST_ARCH_OS),hurd)
+ # login is not built on The Hurd, but some utilities of passwd depends on
+ # /etc/login.defs.
+@@ -87,3 +88,6 @@
+ chgrp shadow debian/passwd/usr/bin/expiry
+ chmod g+s debian/passwd/usr/bin/chage
+ chmod g+s debian/passwd/usr/bin/expiry
++ chgrp groupmems debian/passwd/usr/sbin/groupmems
++ chmod u+s debian/passwd/usr/sbin/groupmems
++ chmod o-x debian/passwd/usr/sbin/groupmems
+--- /dev/null
++++ b/debian/passwd.groupmems.pam
+@@ -0,0 +1,8 @@
++# The PAM configuration file for the Shadow 'groupmod' service
++#
++
++# This allows root to modify groups without being prompted for a password
++auth sufficient pam_rootok.so
++
++@include common-auth
++@include common-account
diff --git a/debian/patches/901_testsuite_gcov b/debian/patches/901_testsuite_gcov
new file mode 100644
index 0000000..717ccca
--- /dev/null
+++ b/debian/patches/901_testsuite_gcov
@@ -0,0 +1,76 @@
+--- a/lib/Makefile.am
++++ b/lib/Makefile.am
+@@ -1,6 +1,8 @@
+
+ AUTOMAKE_OPTIONS = 1.0 foreign
+
++CFLAGS += -fprofile-arcs -ftest-coverage
++
+ DEFS =
+
+ noinst_LTLIBRARIES = libshadow.la
+--- a/libmisc/Makefile.am
++++ b/libmisc/Makefile.am
+@@ -1,6 +1,8 @@
+
+ EXTRA_DIST = .indent.pro xgetXXbyYY.c
+
++CFLAGS += -fprofile-arcs -ftest-coverage
++
+ INCLUDES = -I$(top_srcdir)/lib
+
+ noinst_LIBRARIES = libmisc.a
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -7,6 +7,8 @@
+ suidperms = 4755
+ sgidperms = 2755
+
++CFLAGS += -fprofile-arcs -ftest-coverage
++
+ INCLUDES = \
+ -I${top_srcdir}/lib \
+ -I$(top_srcdir)/libmisc
+--- a/debian/rules
++++ b/debian/rules
+@@ -40,6 +40,12 @@
+ endif
+ export CFLAGS
+
++clean:: clean_gcov
++
++clean_gcov:
++ find . -name "*.gcda" -delete
++ find . -name "*.gcno" -delete
++
+ # Add extras to the install process:
+ binary-install/login::
+ dh_installpam -p login
+--- a/lib/defines.h
++++ b/lib/defines.h
+@@ -174,23 +174,9 @@
+ trust the formatted time received from the unix domain (or worse,
+ UDP) socket. -MM */
+ /* Avoid translated PAM error messages: Set LC_ALL to "C".
++ * This is disabled for coverage testing
+ * --Nekral */
+-#define SYSLOG(x) \
+- do { \
+- char *old_locale = setlocale (LC_ALL, NULL); \
+- char *saved_locale = NULL; \
+- if (NULL != old_locale) { \
+- saved_locale = strdup (old_locale); \
+- } \
+- if (NULL != saved_locale) { \
+- (void) setlocale (LC_ALL, "C"); \
+- } \
+- syslog x ; \
+- if (NULL != saved_locale) { \
+- (void) setlocale (LC_ALL, saved_locale); \
+- free (saved_locale); \
+- } \
+- } while (false)
++#define SYSLOG(x) syslog x
+ #else /* !ENABLE_NLS */
+ #define SYSLOG(x) syslog x
+ #endif /* !ENABLE_NLS */
diff --git a/debian/patches/README.patches b/debian/patches/README.patches
new file mode 100644
index 0000000..a804fe3
--- /dev/null
+++ b/debian/patches/README.patches
@@ -0,0 +1,22 @@
+Small intro to the system for numbering the patches here...
+
+-The 00xx-... patches are forwarded to upstream's git repository
+
+-The 0xx_... series of patches are patches isolated from the latest
+ version of the shadow Debian package not using quilt in order to
+ separate upstream from Debian-specific stuff.
+
+ NO MORE PATCHES SHOULD BE ADDED IN THESE SERIES
+
+-The 4xx series are patches which have been applied to Debian's shadow
+ and have NOT been accepted and/or applied upstream. These patches MUST be kept
+ even after resynced with upstream
+
+-The 5xx series are patches which are applied to Debian's shadow
+ and will never be proposed upstream because they're too specific
+ This list SHOULD BE AS SHORT AS POSSIBLE
+
+In short, while we are working towards synchronisation with upstream,
+our goal is to make 0xx patches disappear by moving them either to 3xx
+series (things already implemented upstream) or to 4xx series
+(Debian-specific patches).
diff --git a/debian/patches/series b/debian/patches/series
new file mode 100644
index 0000000..ba058e0
--- /dev/null
+++ b/debian/patches/series
@@ -0,0 +1,23 @@
+# CVE-2023-4641
+0001-gpasswd-1-Fix-password-leak.patch
+
+# CVE-2023-29383
+0002-Added-control-character-check.patch
+0003-Overhaul-valid_field.patch
+
+# These patches are only for the testsuite:
+#900_testsuite_groupmems
+#901_testsuite_gcov
+
+008_login_log_failure_in_FTMP
+401_cppw_src.dpatch
+# 402 should be merged in 401, but should be reviewed by SE Linux experts first
+402_cppw_selinux
+429_login_FAILLOG_ENAB
+463_login_delay_obeys_to_PAM
+501_commonio_group_shadow
+502_debian_useradd_defaults
+503_shadowconfig.8
+505_useradd_recommend_adduser
+506_relaxed_usernames
+542_useradd-O_option