`\\n` inside square brackets doesn't include or exclude the
newline character. It includes or excludes a literal slash and
the literal character 'n'.
Fixes: c44f1e096a19 (2025-07-20; "chpasswd: Check hash before write when using -e")
Closes: <https://github.com/shadow-maint/shadow/issues/1519>
Signed-off-by: Adam Williamson <awilliam@redhat.com>
This checks the entire shadow(5) 2nd field, which is more than just
a hash.
Reported-by: Tobias Stoeckmann <tobias@stoeckmann.org>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
It represents a passwordless account.
That is discouraged, but accepted.
Fixes: c44f1e096a19 (2025-07-20; "chpasswd: Check hash before write when using -e")
Link: <https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1124835>
Reported-by: Marc 'Zugschlus' Haber <mh+githubvisible@zugschlus.de>
Reported-by: "Serge E. Hallyn" <serge@hallyn.com>
Reported-by: Adam Williamson <awilliam@redhat.com>
Co-authored-by: "Serge E. Hallyn" <serge@hallyn.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
The lrename function follows symlinks when renaming files. Since the
source is a temporary file and the target is the database file itself,
which is opened with O_NOFOLLOW, this function is only useful for an
attacker who manages to win some form of race.
Fixes: 0fa908302660 (2007-10-07; "[svn-upgrade] Integrating new upstream version, shadow (4.0.16)")
Fixes: 391a3847157c (2010-03-04; "2010-01-30 Paweł Hajdan, Jr. <phajdan.jr@gentoo.org>")
Reviewed-by: Alejandro Colomar <alx@kernel.org>
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
Since tmpf has been already renamed to target at this point, call utime
with target instead of tmpf.
Fixes: f8732b17dd1d (2026-01-14; "lib/commonio.c: Use unpredictable temporary names")
Reported-by: Alejandro Colomar <alx@kernel.org>
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
Make sure that enough bytes exist for file name of temporary file which
is used to construct the next database file.
While at it, use a better variable name.
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
Make sure that an attacker with sufficient privileges cannot simply
create a file with expected temporary name to retrieve content of
previous and/or future database.
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
Accessing and setting shadow_progname is not as straight-forward as it
might seem due to the way of linking libshadow_la with libsubid and
programs.
Enforce the usage of log_get_progname to make this less messy.
With last entry of shadowlog_internal.h gone, remove the file entirely.
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
Accessing this variable directly is a recipe for disaster, because
binaries and libraries can have different versions in them due to how
libshadow_la linking is performed.
Make sure that at least NULL check is always performed by calling the
proper getter function.
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
The reset_selinux flag is always true, so it can be removed.
Remove all functions which are not used anymore as well.
Reviewed-by: Alejandro Colomar <alx@kernel.org>
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
This is widely accepted as an invalid hash, to remove password access
for an account (that is, no passwords will match the "hash").
Fixes: c44f1e096a19 (2025-07-20; "chpasswd: Check hash before write when using -e")
Closes: <https://github.com/shadow-maint/shadow/issues/1483>
Closes: <https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1124835>
Reported-by: Chris Hofstaedtler <zeha@debian.org>
Reviewed-by: Chris Hofstaedtler <zeha@debian.org>
Cc: vinz <mmpx09@protonmail.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
A leading '!' means that the account is locked.
Fixes: c44f1e096a19 (2025-07-20; "chpasswd: Check hash before write when using -e")
Link: <https://github.com/shadow-maint/shadow/issues/1483>
Link: <https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1124835>
Reported-by: Chris Hofstaedtler <zeha@debian.org>
Reviewed-by: Chris Hofstaedtler <zeha@debian.org>
Cc: vinz <mmpx09@protonmail.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
While the empty one is more correct, {0} will also work, and will
likely silence diagnostics in old compiler versions.
Empty compound literals are only supported in GCC since commit
gcc.git 14cfa01755a6 (2022-08-25; "c: Support C2x empty initializer braces")
Reported-by: Serge Hallyn <serge@hallyn.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
In general, empty fields in a CSV are errors. However, in some cases,
we want to allow passing empty lists, and the way to encode that is as
an empty string. This was accidentally broken in 4.17.0, when we
switched from using strtok(3) to strsep(3), without remembering to
special-case an empty CSV.
The bug affected directly groupadd(8) and groupmod(8).
The bug also affected the library function add_groups(). In systems
using PAM, that function is unused. On systems without PAM, it is
called by the library function setup_uid_gid(), with the contents of the
"CONSOLE_GROUPS" configuration (login.defs) CSV string.
setup_uid_gid() is directly called by su(1) and login(1) on systems
without PAM.
setup_uid_gid() is also called by the library function expire().
expire() is directly called by expiry(1), su(1), and login(1).
This bug is a regression introduced in the release 4.17.0, and present
in the releases 4.17.{0..4} and 4.18.0.
Fixes: 90afe61003ef (2024-12-05; "lib/, src/: Use strsep(3) instead of strtok(3)")
Link: <https://github.com/shadow-maint/shadow/issues/1420>
Reported-by: Osark Vieira <https://github.com/osark084>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
Some names are bad, and some names are really bad. '--badname' should
only allow the mildly bad ones, which we can handle. Some names are too
bad, and it's not possible to deal with them. Reject them
unconditionally.
- A leading '-' is too dangerous. It breaks things like execve(2), and
almost every command.
- Spaces are used for delimiting lists of users and groups.
- '"' is special in many languages, including the shell. Having it in
user names would be unnecessarily dangerous.
- '#' is used for delimiting comments in several of our config files.
Having it in usernames could result in incorrect configuration files.
- "'" is special in many languages, including the shell. Having it in
user names would be unnecessarily dangerous.
- ',' is used for delimiting lists of users and groups.
- '/' is used for delimiting files, and thus could result in incorrect
handling of users and groups.
- ':' is the main delimiter in /etc/shadow and /etc/passwd.
- ';' is special in many languages, including the shell. Having it in
user names would be unnecessarily dangerous.
There are other characters that we should disallow, but they need more
research to make sure we don't introduce regressions. This set should
be less problematic.
Acked-by: Tobias Stoeckmann <tobias@stoeckmann.org>
Reviewed-by: Iker Pedrosa <ipedrosa@redhat.com>
Reviewed-by: Chris Hofstaedtler <zeha@debian.org>
Cc: Marc 'Zugschlus' Haber <mh+githubvisible@zugschlus.de>
Cc: Serge Hallyn <serge@hallyn.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
The failing function call was wait, not waitpid.
Reviewed-by: Alejandro Colomar <alx@kernel.org>
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
Unify the retrieval of PASS_MIN_LEN and PASS_MAX_LEN for output
in passwd and actual checks.
Fixes wrong output for minimum password lengths if no such
restriction is configured: 5 is printed, 0 is in effect.
How to reproduce:
1. Use passwd compiled without PAM support
2. Do not specify PASS_MIN_LEN in login.defs
3. Run passwd as a user and enter your old password, then
- you will see that 5 characters are expected
- you can just press enter twice
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
The getdef_num implementation allows -1 to be specified in login.defs.
In general, -1 should be treated the same way as "not specified". In
this case, casting -1 to size_t leads to every password being "too
short."
Reviewed-by: Alejandro Colomar <alx@kernel.org>
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
Always start a sentence with lowercase letter after 'Note:', 'Warning:',
etc. This unifies all occurrences.
No functional change.
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
If password aging should not be performed, disable it properly. Just
specifying a "long enough time" is not infinity.
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
The pwd_to_spwd routine claims that fields without corresponding
information in the password file are set to uninitialized values,
but sets some aging information. These cannot be available in
struct passwd.
Also, the code is only used in passwd to temporarily hold the
new password. All other values are copied from an existing entry
later on. If no entry exists, all values are dismissed anyway.
Clarify that everything is uninitialized except name and password.
Gets rid of magic value 10000 for sp_max.
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
Fixes build failure:
```
In file included from xgetgrnam.c:40:
xgetXXbyYY.c: In function ‘xgetgrnam’:
xgetXXbyYY.c:83:31: error: ‘SIZE_MAX’ undeclared (first use in this function)
83 | if (length == SIZE_MAX) {
| ^~~~~~~~
```
Signed-off-by: Mike Gilbert <floppym@gentoo.org>
The 'T' in the name notes that this API is a type-safe variant of the
API it wraps. This makes the names more explicative.
Signed-off-by: Alejandro Colomar <alx@kernel.org>
The 'T' in the name notes that this API is a type-safe variant of the
API it wraps. This makes the names more explicative.
Signed-off-by: Alejandro Colomar <alx@kernel.org>
The 'T' in the name notes that this API is a type-safe variant of the
API it wraps. This makes the names more explicative.
Signed-off-by: Alejandro Colomar <alx@kernel.org>
The 'T' in the name notes that this API is a type-safe variant of the
API it wraps. This makes the names more explicative.
Signed-off-by: Alejandro Colomar <alx@kernel.org>
The 'T' in the name notes that this API is a type-safe variant of the
API it wraps. This makes the names more explicative.
Signed-off-by: Alejandro Colomar <alx@kernel.org>
The 'T' in the name notes that this API is a type-safe variant of the
API it wraps. This makes the names more explicative.
Signed-off-by: Alejandro Colomar <alx@kernel.org>
The 'T' in the name notes that this API is a type-safe variant of the
API it wraps. This makes the names more explicative.
Signed-off-by: Alejandro Colomar <alx@kernel.org>
Casts are unsafe.
Compound literals also have the ability of converting values, but they
don't have the unwanted effects on safety --casts disable most useful
diagnostics--.
Compound literals are lvalues, which means their address can be taken,
and they can also be assigned to. To avoid this, we force lvalue
conversion through a statement expression.
Signed-off-by: Alejandro Colomar <alx@kernel.org>
BTW, getline(3) says we are responsible for free(3)ing the buffer on
error.
Reported-by: Chris Hofstaedtler <zeha@debian.org>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
It seems they never worked correctly. Let's keep it simple and remove
support for escaped newlines.
Closes: <https://github.com/shadow-maint/shadow/issues/1055>
Reported-by: Chris Hofstaedtler <zeha@debian.org>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
Being a macro, the unused return value triggers a diagnostic.
This probably needs further investigation, but we have the issue linked
below for that.
Link: <https://github.com/shadow-maint/shadow/issues/1221>
Reviewed-by: Serge Hallyn <serge@hallyn.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>