When doing update-po, we copy man/*.xml into a tempdir, but
some of those files reference login.defs.d/*.xml, so copy
over those as well.
Signed-off-by: Serge Hallyn <serge@hallyn.com>
Tested-by: Alejandro Colomar <alx@kernel.org>
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>
This wasn't only an optimization; it also skipped some checks that were
now spuriously triggering errors. We may be able to get rid of the
optimizations, but that will need more analysis. For now, let's revert
to a known-good state.
Fixes: 6a8a25dc7de6 (2025-10-15; "src/usermod.c: Remove optimizations")
Reverts: 6a8a25dc7de6 (2025-10-15; "src/usermod.c: Remove optimizations")
Closes: <https://github.com/shadow-maint/shadow/issues/1509>
Reported-by: Adam Williamson <awilliam@redhat.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
Reproducer:
$ useradd foo
$ grep foo /etc/passwd /etc/shadow
/etc/passwd:foo:x:1001:1001::/home/foo:/usr/bin/bash
/etc/shadow:foo:!:20458:0:99999:7:::
$ usermod -U testuser
usermod: unlocking the user's password would result in a passwordless account.
You should set a password with usermod -p to unlock this user's password.
$ echo $?
0
$ grep foo /etc/passwd /etc/shadow
/etc/passwd:foo:x:1001:1001::/home/foo:/usr/bin/bash
/etc/shadow:foo:!:20458:0:99999:7:::
The program failed (didn't change anything, and reported the problem to
stderr) but reported success (0). After this patch, the error is
reported as E_PASSWORDLESS (20).
Closes: <https://github.com/shadow-maint/shadow/issues/1479>
Reported-by: Tobias Stoeckmann <tobias@stoeckmann.org>
Acked-by: Tobias Stoeckmann <tobias@stoeckmann.org>
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>
The fmkomstemp call requires a suffix of XXXXXX for correct operation.
Do so in TCB case as well.
Note: If something fails and the file resides in this directory, it
could be interpreted as a username. Use the ',' character as an illegal
character to prevent shadow tools from erroneously accessing this file
and assuming that the user actually exists.
Fixes: a5b3d56e2902 (2026-01-09; "vipw: Use fmkomstemp for temporary file")
Reported-by: Alejandro Colomar <alx@kernel.org>
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
This is a safer approach, which handles cases in which a file would have
less permissions for a group than others.
A rare edge case, but let's be safe than sorry.
Reported-by: Alejandro Colomar <alx@kernel.org>
Reviewed-by: Alejandro Colomar <alx@kernel.org>
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
Use file descriptor functions when file descriptor is available, instead
of path based operations. The latter resolve symbolic links and are
prone to race conditions.
Reported-by: Alejandro Colomar <alx@kernel.org>
Reviewed-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>
Do not call any shadowlog functions directly from program source files
which are also linked with libsubid.
Both, the program and the library, will have their own version of the
static variables within shadowlog.c and thus would have different
logging mechanisms.
Use subid_init instead.
Reviewed-by: Alejandro Colomar <alx@kernel.org>
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
Since this is no signal handler anymore, allow regular exit routine to
flush stderr etc.
Reviewed-by: Alejandro Colomar <alx@kernel.org>
Reviewed-by: Ruihan Li <lrh2000@pku.edu.cn>
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
The pid_child is never 0 when reaching kill_child, since kill_child
is called within an if-block which checks explicitly for pid_child not
being 0.
Reviewed-by: Alejandro Colomar <alx@kernel.org>
Reviewed-by: Ruihan Li <lrh2000@pku.edu.cn>
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
The pid_child can be passed into kill_child, since it is no signal
handler anymore.
Reviewed-by: Alejandro Colomar <alx@kernel.org>
Reviewed-by: Ruihan Li <lrh2000@pku.edu.cn>
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
Since kill_child is no signal handler any longer, it is safe to call the
gettext macros directly and only when needed.
Reviewed-by: Alejandro Colomar <alx@kernel.org>
Reviewed-by: Ruihan Li <lrh2000@pku.edu.cn>
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
This simplifies the alarm handler to just set a volatile
sig_atomic_t like catch_signals does, which makes the handler way
easier to review.
Reviewed-by: Alejandro Colomar <alx@kernel.org>
Reviewed-by: Ruihan Li <lrh2000@pku.edu.cn>
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
Only these shared variables can be safely written to by signal handlers.
Reviewed-by: Alejandro Colomar <alx@kernel.org>
Reviewed-by: Ruihan Li <lrh2000@pku.edu.cn>
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
It could happen that, if SIGCHLD was set to SIG_IGN before calling vipw,
the forked child is already gone before SIGCHLD is set to SIG_DFL after
the fork.
Prevent this race condition and also properly set up SIGCHLD for child
handling within the fork, even though system() should take care of that.
Reviewed-by: Alejandro Colomar <alx@kernel.org>
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>
If TCB is not in use, the whole configuration section is a stub,
containing no useful information. Make it conditional so it
disappears if TCB is not in use.
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
Add comprehensive test for the groupmod -U option when provided with a
list of users to set group membership. This test verifies:
- Setting initial group membership with multiple users
- Proper membership verification in both group and gshadow entries
- Updating group membership by modifying the user list
- Correct handling of membership changes in group databases
Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
GShadowEntry administrators and members represent a list of usernames,
not a single string. Thus, set them to `list[str]`. This fixes type
safety and clarifies the expected data structure.
Fixes: 458700b5d670 (2025-09-10; "tests/system/framework/: fix Python linter issues")
Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
Breaking changes:
- Remove support for escaped newlines in configuration files.
It never worked correctly.
b0a7ce58b924 (2025-12-05; "lib/, po/: Remove fgetsx() and fputsx()")
- Some user names and group names are too dangerous and are rejected,
even with --badname.
25aea7422615 (2025-12-25; "lib/chkname.c, src/: Strictly disallow really bad names")
Future breaking changes:
- SHA512 and SHA256 will be supported unconditionally in the next
release. The build-time flag '--with-sha-crypt' will be removed.
See <https://github.com/shadow-maint/shadow/pull/1452>.
Support:
- Several years ago, there were talks about deprecating su(1) and
login(1), back when this project was maintained as part of Debian.
However, nothing was clearly stated, and there were doubts about the
status of these programs. Let's clarify them now.
Our implementations of su(1) and login(1) are fully supported, and we
don't have any plans to remove them. They are NOT deprecated.
See <https://github.com/shadow-maint/shadow/issues/464>.
Deprecations:
- groupmems(8)
The program will be removed in a future release.
See <https://github.com/shadow-maint/shadow/issues/1343>.
- logoutd(8)
The program will be removed in the next release.
See <https://github.com/shadow-maint/shadow/issues/999>,
and <https://github.com/shadow-maint/shadow/pull/1344>.
- DES
This hashing algorithm has been deprecated for a long time,
and support for it will be removed in a future release.
See <https://github.com/shadow-maint/shadow/pull/1456>
- MD5
This hashing algorithm has been deprecated for a long time,
and support for it will be removed in a future release.
See <https://github.com/shadow-maint/shadow/pull/1457>
- login.defs(5): MD_CRYPT_ENAB
This feature had been deprecated for decades. It will be
removed in a future release.
The command-line equivalents (-m, --md5) of this feature in
chpasswd(8) and chgpasswd(8) will also be removed in a future
release.
See <https://github.com/shadow-maint/shadow/pull/1455>.
- login.defs(5): PASS_MAX_LEN
This feature is ignored except for DES. Once DES is removed,
it makes no sense keeping it. It may be removed in a future
release.
- Password aging
Scientific research shows that periodic password expiration
leads to predictable password patterns, and that even in a
theoretical scenario where that wouldn't happen the gains in
security are mathematically negligible.
<https://people.scs.carleton.ca/~paulv/papers/expiration-authorcopy.pdf>
Modern security standards, such as NIST SP 800-63B-4 in the USA,
prohibit periodic password expiration.
<https://pages.nist.gov/800-63-4/sp800-63b.html#passwordver>
<https://pages.nist.gov/800-63-FAQ/#q-b05>
<https://www.ncsc.gov.uk/collection/passwords/updating-your-approach#PasswordGuidance:UpdatingYourApproach-Don'tenforceregularpasswordexpiry>
To align with these, we're deprecating the ability to
periodically expire passwords. The specifics and long-term
roadmap are currently being discussed, and we invite feedback
from users, particularly from those in regulated environments.
See <https://github.com/shadow-maint/shadow/pull/1432>.
This deprecation includes the following programs and features:
expiry(1)
chage(1):
-I,--inactive (also the interactive version)
-m,--mindays (also the interactive version)
-M,--maxdays (also the interactive version)
-W,--warndays (also the interactive version)
passwd(1):
-k,--keep-tokens
-n,--mindays
-x,--maxdays
-i,--inactive
-w,--warndays
useradd(8):
-f,--inactive
usermod(8):
-f,--inactive
login.defs(5):
PASS_MIN_DAYS
PASS_MAX_DAYS
PASS_WARN_AGE
/etc/default/useradd:
INACTIVE
shadow(5):
sp_lstchg: Restrict to just the values 0 and empty.
sp_min
sp_max
sp_warn
sp_inact
We recognize that many users operate in environments with
regulatory or contractual requirements that still mandate
password aging. To minimize disruption, these features will
remain functional for a significant period. However, we
encourage administrators to review their internal policies,
talk to their regulators if appropriate, and participate in the
roadmap discussion linked above.
Co-authored-by: Iker Pedrosa <ipedrosa@redhat.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
I don't know what this commit does, to be honest. I just
did './autogen.sh && make && make dist' and committed the
changes to .po files. Why? I don't know.
BTW, I kept out some changes that were actually bad.
Signed-off-by: Alejandro Colomar <alx@kernel.org>
I don't know what this commit does, to be honest. I just
did './autogen.sh && make && make dist' and committed the
changes to .pot files. Why? I don't know.
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>
Only one opening bracket is used before two closing brackets are
encountered for "(--user)".
Drop redundant ones within the file.
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
Use tab instead of spaces to comply with rest of files.
Fixes: 923aeac250d0 (2025-07-04; "man/: update `--root` flag with no SELinux support")
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
The usage message of sg and synopsis of its manual page diverged. The
difference was even noted in a comment, instead of fixing it.
Synchronize both, add information about hidden options and document
what they do.
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
Use "an" in front of sg due to its pronounciation. Also, start a comment
with capital letter in its first sentence to comply with other comments.
No functional change.
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.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>
Actually log the user name as done with stderr message.
Reviewed-by: Alejandro Colomar <alx@kernel.org>
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
The failing function call was wait, not waitpid.
Reviewed-by: Alejandro Colomar <alx@kernel.org>
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
Duplicating name and hash is not needed here, because duplication
occurs in spw_update. You can detect the small memory leak with
tools like valgrind.
More importantly though, if xstrdup fails, it calls exit. The
update_age function is in the "criticial section" between
open_files and close_files, though. Correct error handling would
require fail_exit to release the held locks.
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
The gpasswd utility was segfaulting when cleanup functions were called
because these functions expect a pointer to `process_selinux` but was
being passed NULL. This caused a NULL pointer dereference.
This commits adds the pointer to `process_selinux` to clean up
functions making `gpasswd` consistent with other group utilities.
Reproduction steps:
$ useradd tuser
$ groupadd tuser
$ gpasswd -a tuser tgroup
Adding user tuser to group tgroup
Segmentation fault (core dumped)
Fixes: 4d431898bad8 (2025-10-07; "src/gpasswd.c: chroot or prefix SELinux file context")
Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
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>
The check_fds function is supposed to ensure that fds 0, 1, and 2 are
opened in a well-defined state, i.e. either they are already connected
to supposed input/output files or will be connected to /dev/null if not.
Opening the audit socket before checking the fds allows the audit socket
to get one of these numbers.
Avoid this by opening the audit socket after the check.
In general, this check is already covered by system libraries, but this
proof of concept works for root user. Note the different states of the
file descriptor 2.
In bash or another shell that interprets `2>&-` as closing stderr with
shadow + audit support, e.g. Arch Linux:
```
sg bin 'ls -l /proc/self/fd'
sg bin 'ls -l /proc/self/fd' 2>/dev/null
sg bin 'ls -l /proc/self/fd' 2>&-
```
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
The `PASS_MAX_LEN` is effectively only used for DES. Do not describe it
in a way that makes it sound like `MD_CRYPT_ENAB=yes` is required to
disable it. Any other `ENCRYPT_METHOD` disables it as well.
Also, even for DES, `PASS_MAX_LEN` requires `OBSCURE_CHECKS_ENAB` to
have any effect.
Even more, `PASS_MIN_LEN` and `PASS_MAX_LEN` are only used for
user passwords. Group passwords are not checked.
Note: All of this is actually true even if compiled with PAM if command
line arguments change root. But if compiled with PAM support, this
section is not added to manual pages... Since this is true for some
more files, it's not part of this commit.
Link to source files:
- lib/obscure.c line 133 stops further checks, including max length,
if OBSCURE_CHECS_ENAB is not yes
- lib/obscure.c line 172 is only reached in case of DES
- src/passwd.c line 248 duplicates the check for output
- src/gpasswd.c has no reference to obscure
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
Even though this is technically no sentence, it stays in sync with the
other file descriptions this way.
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>
Shadow password files do not necessarily need aging information.
Also, passwd has no aging information.
No conversion is performed, so drop the comment entirely.
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
- The total number of password change tries can be configured
- Except min length, password strength checks can be disabled
- Even the root user can have password strength checks...
- ... except in some cases (stdin, command line arguments)
In general, this code does not run for PAM, except root directory
is modified through command line arguments by root user.
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
The passwd tool checks if the password of a user may be changed before
locking the passwd/shadow files. This leaves a time window to perform
the same action twice (e.g. circumventing PASS_MIN_DAYS limit) or to
circumvent a locked password by an administrator.
Perform the check after the lock again. This keeps the behavior as it
is today for a user and also prevents the race condition.
Reviewed-by: Alejandro Colomar <alx@kernel.org>
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
Calling fail_exit here prepares an upcoming commit to reuse the
functions when databases have been locked.
Reviewed-by: Alejandro Colomar <alx@kernel.org>
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
Always use the name in shadow entry for logging. This reduces the
amount of data retrieved from password entry to bare minimum, i.e.
passing through into library call.
Reviewed-by: Alejandro Colomar <alx@kernel.org>
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
Make sure that passwd and shadow are always opened in the correct
order to avoid possible dead locks with other tools:
- Lock passwd first, then shadow
- Unlock shadow first, then passwd
The passwd utility may work without a shadow entry. In that case, it
operates on the passwd file. But to figure this out, the shadow file
must have been opened and thus locked already. Unconditionally open the
passwd file first, even though it's not needed most of the time.
Reviewed-by: Alejandro Colomar <alx@kernel.org>
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
At this point, shadow might be already locked if update_noshadow is
called as fallback within update_shadow. Make sure that unlock is
called before exit.
Fixes: 45c6603cc86c (2007-10-07; "[svn-upgrade] Integrating new upstream version, shadow (19990709)")
Reviewed-by: Alejandro Colomar <alx@kernel.org>
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
No need to re-evaluate option_flags in functions. Unifies checks and
simplifies code.
Reviewed-by: Alejandro Colomar <alx@kernel.org>
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
If PASS_MAX_DAYS is not set, newusers falls back to 10000 days, which is
considered "unlimited" in some parts of the source tree. All other tools
fall back to -1, which truely implies unlimited.
Sync newusers with all other shadow tools.
How to reproduce:
1. Remove or comment out PASS_MAX_DAYS from /etc/login.defs
2. Run `newusers <<< user:pass:1234🔢:/home/user:/bin/bash`
3. Check user line in /etc/shadow
```
/etc/shadow:user:HASH:19721:0:10000:7:::
```
Max days are set to 10000. Instead, this should be:
```
/etc/shadow:user:HASH:19721:0::7:::
```
Reviewed-by: Alejandro Colomar <alx@kernel.org>
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>
This is the transformation to Python of the test located in
`tests/grouptools/groupmems/01_groupmems_root_add_user/groupmems.test`,
which checks that `groupmems` is able to add a user to a group running
as the root user.
Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
Temporary workaround to create the groupmems PAM service file. Fedora
will soon provide this service file and we'll be able to remove the
workaround.
Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
This is the transformation to Python of the test located in
`tests/newusers/20_multiple_users/newusers.test`, which checks that
`newusers` is able to create new users from file.
Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
This is the transformation to Python of the test located in
`tests/newusers/35_read_from_stdin/newusers.test`, which checks that
`newusers` is able to create new users from stdin.
Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
Temporary workaround to create the newusers PAM service file. Fedora
will soon provide this service file and we'll be able to remove the
workaround.
Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
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>
[Serge: preference to keep the names as a comment, but ok]
Reviewed-by: Serge Hallyn <serge@hallyn.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
[Serge: preference to keep the names as a comment, but ok]
Reviewed-by: Serge Hallyn <serge@hallyn.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
A possible use case for this is wanting to add subuid/subgid entries for
an existing user. This change makes it possible to pass `username::::::`
to newusers; the empty password will be ignored an everything else will
be done. Currently this fails miserably, as PAM errors out on a empty
password.
Signed-off-by: Antonio Terceiro <terceiro@debian.org>
This macro is like typeof(), but requires that the input is a type name.
This macro is useful because it parenthesizes the type name, which
allows one to create pointers to arbitrary types. The following code
works for simple types:
T x;
T *p;
For example, that would work fine for 'int':
int x;
int *p;
However, that wouldn't work for types such as 'int[3]':
int[3] x;
int[3] *p;
But if we do instead
typeas(T) x;
typeas(T) *p;
now we can use 'int[3]' just fine:
typeof((int[3]){}) x;
typeof((int[3]){}) *p;
To understand this, we create a compound literal of type int[3], with
default values (zero, zero, zero), then get it's type, which is
obviously int[3]. And then we use that to declare a variable x of that
type, and a pointer p, which has type 'int(*)[3]'.
This would also work with something simpler. One could use typeof(T)
directly:
typeof(T) x;
typeof(T) *p;
However, typeof() doesn't require that the input is a type; it accepts
arbitrary input. The following is valid C:
typeof(42) x;
For our macro MALLOC(), where we want the second argument to be a type
name, we want to require that the argument is a type name. For that, we
need to use typeas().
Reported-by: Alejandro Colomar <alx@kernel.org>
Suggested-by: Thiago Adams <thiago.adams@gmail.com>
Suggested-by: Martin Uecker <uecker@tugraz.at>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
Have xxx_T() macros that only add type safety to the function they wrap.
Have XXX() macros that do more magic; in this case, they deduce the
comparison function that is appropriate for the type.
This will allow using the xxx_T() macros in more complex cases, where
the function can't be deduced just from the type.
Signed-off-by: Alejandro Colomar <alx@kernel.org>
This simplifies the implementation, allowing us to use _Generic(3) to
replace _Static_assert(3), is_same_type(), and local variables.
Local variables in macros can cause issues when nesting such macros.
This also makes the code more readable, by having the type explicitly
stated at call site.
Signed-off-by: Alejandro Colomar <alx@kernel.org>
In all these functions, we were setting the flags to 'true' in
process_flags() if the appropriate command-line flag was specified.
However, they were never being defined to 'false', which should be the
default value. Initialize these flags to false.
Fixes: c0c9485d9a5a (2025-10-07; "src/useradd.c: chroot or prefix SELinux file context")
Link: <https://github.com/shadow-maint/shadow/pull/1396>
Reviewed-by: Serge Hallyn <serge@hallyn.com>
Cc: Iker Pedrosa <ipedrosa@redhat.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
I just did a 'make dist', then committed the updates to the po and
shadow.pot files.
Closes#1359
Signed-off-by: Serge Hallyn <serge@hallyn.com>
CC: Chris Hofstaedtler <zeha@debian.org>
FTR: I'm not entirely sure if an empty string can arrive here. It might
be that the streq() check is dead code, but I'm not sure, so I put it.
It also makes the code more robust.
Signed-off-by: Alejandro Colomar <alx@kernel.org>
'make distcheck' runs ./configure (among other things). That command
should inherit the flags passed on the command line, as they are the
flags necessary to build in the current system.
This also allows testing different configurations in the same system.
Until now, we only tested the default automagic configuration. With
this change, one can test the same default automagic configuration, by
not passing any flags to ./configure, or they can test more specific
configurations, by passing flags.
This allows removing the hardcoded AM_DISTCHECK_CONFIGURE_FLAGS in the
"Makefile.am".
Signed-off-by: Alejandro Colomar <alx@kernel.org>
memcpy(3) is overkill, and much more dangerous than simple assignment.
Simple assignment adds type safety, and removes any possibility of
buffer overflow due to accidentally specifying a wrong size.
Signed-off-by: Alejandro Colomar <alx@kernel.org>
By returning the new pointer, we can simplify the implementation,
and we avoid a return-by-parameter.
Signed-off-by: Alejandro Colomar <alx@kernel.org>
fgets(3) returns either NULL or the input pointer. Checking for NULL is
more explicit, and simpler.
<stddef.h> is the header that provides NULL; add it where appropriate.
The meat of this patch can be approximated with the following semantic
patch:
$ cat ~/tmp/spatch/fgets_null.sp
@@
expression a, b, c;
@@
- fgets(a, b, c) == a
+ fgets(a, b, c) != NULL
@@
expression a, b, c;
@@
- fgetsx(a, b, c) == a
+ fgetsx(a, b, c) != NULL
@@
expression a, b, c, p;
@@
- p->cio_fgets(a, b, c) == a
+ p->cio_fgets(a, b, c) != NULL
@@
expression a, b, c;
@@
- fgets(a, b, c) != a
+ fgets(a, b, c) == NULL
@@
expression a, b, c;
@@
- fgetsx(a, b, c) != a
+ fgetsx(a, b, c) == NULL
@@
expression a, b, c, p;
@@
- p->cio_fgets(a, b, c) != a
+ p->cio_fgets(a, b, c) == NUL
Applied as
$ find contrib/ lib* src/ -type f \
| xargs spatch --sp-file ~/tmp/spatch/fgets_null.sp --in-place;
The differences between the actual patch and the approximation via the
semantic patch from above are includes, whitespace, braces, and a case
where there was an implicit pointer-to-bool comparison which I made
explicit. When reviewing, it'll be useful to use git-diff(1) with '-w'
and '--color-words=.'.
Signed-off-by: Alejandro Colomar <alx@kernel.org>
This patch can be replicated with the following semantic patch:
$ cat fgets_cast.sp
@@
expression a, b, c;
@@
- fgets(a, (int) (b), c)
+ fgets(a, b, c)
@@
expression a, b, c;
@@
- fgets(a, (int) b, c)
+ fgets(a, b, c)
@@
expression a, b, c;
@@
- fgetsx(a, (int) (b), c)
+ fgetsx(a, b, c)
@@
expression a, b, c;
@@
- fgetsx(a, (int) b, c)
+ fgetsx(a, b, c)
@@
expression a, b, c, p;
@@
- p->cio_fgets(a, (int) (b), c)
+ p->cio_fgets(a, b, c)
@@
expression a, b, c, p;
@@
- p->cio_fgets(a, (int) b, c)
+ p->cio_fgets(a, b, c)
which is applied as:
$ find lib* src/ -type f \
| xargs spatch --sp-file ~/tmp/spatch/fgets_cast.sp --in-place;
Signed-off-by: Alejandro Colomar <alx@kernel.org>
Document the new Python system tests:
- Benefits
- Contribution guidance
- How to setup the testing environment
- Test configuration and execution
- Advanced testing features
- Development patterns
- Debugging information
- Troubleshooting & FAQs
Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
Compound literals are lvalues. This means it's possible to take their
address. That is, it would be possible (albeit nonsensical) to do
&strerrno();
It is also possible to assign to them (albeit also nonsensical):
strerrno() = NULL;
The statement expression performs lvalue conversion, which turns the
lvalue into an "rvalue", as expected, and disallows all those issues.
Signed-off-by: Alejandro Colomar <alx@kernel.org>
This name better reflects that it handles arrays, and doesn't shout.
This case is slightly different, as this macro does a little bit more
than just enforcing arrays. It changes the return value too. However,
that is related-enough to the handling of arrays that I'm inclined to
accept it as a minor inconsistency.
Signed-off-by: Alejandro Colomar <alx@kernel.org>
Synopsis
int a2i(typename T, T *restrict n, QChar *s,
QChar **_Nullable restrict endp, int base,
T min, T max);
Description
This macro converts the initial portion of the string pointed to
by 's' to an integer of base 'base', ensure that the number is
in the range [min, max], and store it in *n.
It is similar to NetBSD's strtoi(3) and strtou(3), which
themselves are similar to strtol(3) and strtoul(3).
Arguments
T
The integer type used for the number.
n
A pointer to an integer. The parsed number will be
stored there.
s
See strtol(3).
endp
See strtol(3). A difference with strtol(3) is that this
macro is const-correct. If 's' has type 'const char *',
then 'endp' must have type 'const char **', whereas if
's' has type 'char *', 'endp' must have type 'char **'.
base
See strtol(3).
min
max
See strtoi(3) and strtou(3).
An important difference with NetBSD's strtou(3) is that
a2i() (with an unsigned type T) doesn't intepret any
negative numbers as if they were large positive numbers.
a2i() respects the limits [min, max] as one would
intuitively expect.
Return value
On success, 0 is returned.
On error, -1 is returned and errno is set to indicate the error.
Errors
See strtoi(3) and strtou(3).
Examples
if (a2i(pid_t, &pid, s, &s, 10, 1, _Maxof(pid_t)) == -1)
goto err;
Signed-off-by: Alejandro Colomar <alx@kernel.org>
This macro is useful to implement QChar versions of functions.
See ISO C23 for a description of what QChar is.
Signed-off-by: Alejandro Colomar <alx@kernel.org>
Missing files have been added for the test to work: `gshadow`, `passwd`, `shadow`.
Without them, the foo user was created with a different UID and thus the test failed.
And other minor improvements, such as removing extra spaces and adding empty lines.
Both are indirect tests for exit_if_null(), but through XMALLOC() we
can test it more robustly, as we don't need to wrap vasprintf(3) to
make it fail. It's trivial to make MALLOC(3) fail: pass a huge size.
The tests with xaprintf() were failing on Nix. I suspect the compiler
was inlining aggressively, and as a result, the interposition of
vasprintf(3) in cmocka wasn't actually working. The approach with
XMALLOC() seems to work on Nix, as we don't need to interpose malloc(3).
We still need to interpose exit(3), but for some reason that works fine.
Closes: <https://github.com/shadow-maint/shadow/issues/1382>
Reported-by: Silvan Mosberger <github@infinisil.com>
Tested-by: Silvan Mosberger <github@infinisil.com>
Reviewed-by: Iker Pedrosa <ipedrosa@redhat.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
This test is actually for exit_if_null(), not xaprintf(). Rename the
test file and functions, and make strings more generic.
Tested-by: Silvan Mosberger <github@infinisil.com>
Reviewed-by: Iker Pedrosa <ipedrosa@redhat.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
Propagate the removal of dead code to its callers, which were only
passing the parameter to this function.
Signed-off-by: Alejandro Colomar <alx@kernel.org>
And use it instead of its pattern.
This macro enforces correct use of ttyname_r(3) with arrays.
Reviewed-by: Serge Hallyn <serge@hallyn.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
The method for checking for truncation was quite weird. By not caching
ttyname(3), we use it directly, without needing a temporary copy, which
removes opportunities for bugs.
Reviewed-by: Serge Hallyn <serge@hallyn.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
Writing an x*() variant function of several functions is unnecessary.
It's simpler to write a generic exit_if_null() macro that can be chained
with any other calls. With such a macro, the x*() variants can be
implemented as one-liner macros that are much easier to read:
For example:
#define xmalloc(size) exit_if_null(malloc(size))
If an error is detected, log an error, and exit(13). About why 13, I
don't really know. It's just what was used previously in xmalloc().
Signed-off-by: Alejandro Colomar <alx@kernel.org>
This structure has members that are named like libc APIs.
libc is allowed to provide any functions as macros (7.1.4p1 in C23).
This means that libc is allowed to provide a free(3) macro, which could
look like
#define free(p) __free(p)
And that would be expanded by the preprocessor in our code, turning our
structure members into some code that won't work (or even worse, it
might misbehave).
So, fix this undefined behavior.
Signed-off-by: Alejandro Colomar <alx@kernel.org>
These optimizations checked if the old value is the same as the new
value, and skip such changes. This was unnecessary, and added
complexity to the source code.
Signed-off-by: Alejandro Colomar <alx@kernel.org>
No news is good news.
Debian needs to parse this message to ignore it, or alternatively check
if the call will be a no-op (which we already do) and skip the call.
If we remove this output, we're allowing Debian to remove that
complexity in their wrapper.
We don't expect this output to be very useful for interactive use
either.
Also, this message was changed from stderr to stdout recently, so we
don't need to worry about old scripts that might break due to this
change. If there were scripts relying on that, they would have been
broken already in the previous change.
Closes: <https://github.com/shadow-maint/shadow/issues/1361>
Reported-by: Marc Haber <githubvisible@zugschlus.de>
Cc: <https://github.com/cachius>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
Do not process SELinux file context when running fail_exit() when chroot
or prefix options are selected.
Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
Do not process SELinux file context when running fail_exit() when chroot
or prefix options are selected.
Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
Do not process SELinux file context when running fail_exit() when chroot
or prefix options are selected.
Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
Do not process SELinux file context when running fail_exit() when chroot
or prefix options are selected.
Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
Do not process SELinux file context when running fail_exit() when chroot
or prefix options are selected.
Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
Do not process SELinux file context when running fail_exit() when chroot
or prefix options are selected.
Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
Do not process SELinux file context when running fail_exit() when chroot
or prefix options are selected.
Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
Do not process SELinux file context when running fail_exit() when chroot
or prefix options are selected.
Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
Do not process SELinux file context when running fail_exit() when chroot
or prefix options are selected.
Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
Do not process SELinux file context when running fail_exit() when chroot
or prefix options are selected.
Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
Do not process SELinux file context when running fail_exit() when chroot
or prefix options are selected.
Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
Do not process SELinux file context when running fail_exit() when chroot
or prefix options are selected.
Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
Do not process SELinux file context when running fail_exit() when chroot
or prefix options are selected.
Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
Do not process SELinux file context during file closure when chroot or
prefix options are selected.
Closes: https://github.com/shadow-maint/shadow/issues/940
Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
Expand cleanup_unlock_passwd(), cleanup_unlock_shadow(),
cleanup_unlock_group() and cleanup_unlock_gshadow() interfaces to add a
control flag for SELinux file context processing.
Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
Do not process SELinux file context when running fail_exit() when chroot
or prefix options are selected.
Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
Do not process SELinux file context when running fail_exit() when chroot
or prefix options are selected.
Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
Do not process SELinux file context when running fail_exit() when chroot
or prefix options are selected.
Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
Do not process SELinux file context when running fail_exit() when chroot
or prefix options are selected.
Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
Do not process SELinux file context when creating home and mail folders
when chroot or prefix options are selected.
Closes: https://github.com/shadow-maint/shadow/issues/940
Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
Do not process SELinux file context during file closure when chroot or
prefix options are selected.
Closes: https://github.com/shadow-maint/shadow/issues/940
Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
This macro is provided by glibc (but not musl) as _PATH_GSHADOW in
<paths.h>. Let's use that macro, and define it only if libc doesn't
provide it.
Signed-off-by: Alejandro Colomar <alx@kernel.org>
While the return value is a pointer, it can be interpreted as a boolean
value meaning "found". In general, we use explicit comparisons of
pointers to NULL, but in this specific case, let's use that
interpretation, and make an exception, using an implicit conversion to
boolean.
For negative matches, use
if (!strchr(...))
For positive matches, use
if (strchr(...))
For positive matches, when a variable is also set, use
while (NULL != (p = strchr(...)))
Signed-off-by: Alejandro Colomar <alx@kernel.org>
Move 'want_sub[ug]ids' from 'src/newusers.c' to 'lib/subordinateio.[ch]'
and rename them to 'want_sub[ug]id_file' to clearly indicate that it
refers to the '/etc/sub[ug]id' and not to subids in general.
Restructure the paragraphs to avoid duplication of text inside multiple
conditions, making maintenance easier and avoiding accidental
duplication in the rendered output.
Signed-off-by: Georg Pfuetzenreuter <mail@georg-pfuetzenreuter.net>
The section about the risk of placing a restricted shell was duplicated
in the rendered manual page if the "without_vendordir" condition
matched.
Fixes: a27d5c51f1f3 ("Supporting vendor given -shells- configuration file")
Signed-off-by: Georg Pfuetzenreuter <mail@georg-pfuetzenreuter.net>
Install `gpg` package as Debian 13 container image stopped installing it
by default, making the CI fail.
Closes: <https://github.com/shadow-maint/shadow/issues/1335>
Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
The pointer returned by getutxent() function may always point to
the same shared and reused buffer.
Instead of copying the utmp entry pointer value the content of utmp
entry must be copied otherwise the next call of getutxent() will
overwrite previously found entry.
This commit has no optimisations to highlight what is really fixed.
Fixes: 841776561f56bae7382c6bd47e428201a155d39c (09-08-2025; "lib/utmp.c: Fix umtp entry search")
Signed-off-by: Evgeny Grin (Karlson2k) <k2k@drgrin.dev>
This allows us to split the formation of the string into several
s*printf() calls.
Shorten comment, to make it fit in one line.
Signed-off-by: Alejandro Colomar <alx@kernel.org>
Use a buffer of the exact size we want, and let SNPRINTF() decide if it
fits or not.
BTW, the old check seemed to be wrong: it wasn't accounting for the
commas in the 80-character limit, but that didn't make much sense.
Signed-off-by: Alejandro Colomar <alx@kernel.org>
This wrapper was very weird, and it's simpler to open-code the calls to
strsep(3) and strcpy(3) instead.
Signed-off-by: Alejandro Colomar <alx@kernel.org>
According to the Wikipedia page for the 'Gecos field', the "typical"
format for the GECOS field is a comma-delimited list with this order:
1) User's full name (or application name, if the account is for a program)
2) Building and room number or contact person
3) Office telephone number
4) Home telephone number
5+) Any other contact information (pager number, fax, external e-mail address, etc.)
But our code supported the "other contact information", which we call
slop, and which is composed of an arbitrary number of key=value fields,
to appear before any of the other 4 fields.
This seems to be undocumented, and none of the documentation I've found
for the GECOS field in any systems I checked claims to support this.
By removing support for those, we can significantly simplify the
copy_field() function, which was quite unreadable.
After this patch, the GECOS field is treated as a CSV, blindly copying
the fields as they appear, where the first 4 fields are as specified
above, and anything after them is the slop (5+ fields, any other contact
information).
Signed-off-by: Alejandro Colomar <alx@kernel.org>
This is safer, since in general, readpassphrase(3) does not accept
a null pointer as input.
This was discovered thanks to Chris Bazley's _Optional qualifier, which
I'm testing at the moment.
Signed-off-by: Alejandro Colomar <alx@kernel.org>
In conditions that perform simple assignment (=) before comparison,
it's safer to put the comparison first, as a mistake would result in a
compiler error, as opposed to assigning something incorrect.
It's also more readable, IMO.
Signed-off-by: Alejandro Colomar <alx@kernel.org>
Updated utmp entry search algorithm to follow GNU/Linux description:
https://man7.org/linux/man-pages/man5/utmp.5.html#DESCRIPTION
An entry is found by looking for matching PID. If several such entries
found (for example, due to cleanup failure of old entries) then first
entry with both matching PID and matching 'ut_line' (current terminal)
is used. If not entry has matching 'ut_line' then first entry with
matching PID is used (if getty/init process does not set 'ut_line').
When no single entry is matched by PID, then but at least one entry is
matched current terminal the the first such entry is selected (if getty
does not set correct PID).
This commit uses non-portable Elvis operator is it is already used
everywhere in the code.
Signed-off-by: Evgeny Grin (Karlson2k) <k2k@drgrin.dev>
Before this commit, if configured with --enable-logind, but libsystemd
is not found, configure silently succeed, however logind is efficiently
disabled.
With this commit, the configure fails if logind is not explicitly
disabled and libsystemd is not found.
--disable-logind is mandatory if logind integration should not be used.
Automatic detection is disabled by Alejandro Colomar's request.
Extra help in the error message is added by lslebodn's request.
Signed-off-by: Evgeny Grin (Karlson2k) <k2k@drgrin.dev>
Improve formatting and readability of single configure check.
Also remove unneeded overquoting of "LIBSYSTEMD=-lsystemd".
Signed-off-by: Evgeny Grin (Karlson2k) <k2k@drgrin.dev>
The code does not enabled logind unconditionally by default. Instead
configure checks for logind (libsystemd) availability and enables it
only if found.
Signed-off-by: Evgeny Grin (Karlson2k) <k2k@drgrin.dev>
Add is_valid_hash to prevent adding a bad hash in /etc/shadow (and so prevent user to be lock) when using chpasswd -e
# before
echo 'vinz:test123' | chpasswd -e
grep vinz /etc/shadow
vinz:test123:20280:0:99999:7:::
# now
echo 'vinz:test123' | sudo ./chpasswd -e
chpasswd: (line 1, user vinz) invalid password hash
chpasswd: error detected, changes ignored
This is a workaround for broken shells, which incorrectly performs
'test "$var" = "value"' when variable is empty or not set.
Also this is a guard for variable values that may break "test", like
"!", "-z", "-n".
Signed-off-by: Evgeny Grin (Karlson2k) <k2k@drgrin.dev>
Reviewed-by: Alejandro Colomar <alx@kernel.org>
[[]] means "use literally, without expansion and substitution".
# symbol potentially could be interpreted as a comment.
Also fixed one check with indented " #include <security/pam_appl.h>"
which is not correct C syntax.
Signed-off-by: Evgeny Grin (Karlson2k) <k2k@drgrin.dev>
AC_ARG_ENABLE() expands to nothing where it is used, but adds arguments
parsing, help message and other related things.
It does not make any sense to put this macro into if branch. It may
also confuse the reader.
Signed-off-by: Evgeny Grin (Karlson2k) <k2k@drgrin.dev>
Always quoting of all arguments is recommended by autoconf manual.
The commit is checked by autoreconf -v before and after commit.
Resulting configure is identical (excluding some newlines).
Signed-off-by: Evgeny Grin (Karlson2k) <k2k@drgrin.dev>
Lines were incorrectly added by 5cd04d03f94622c12220d4a6352824af081b8531
The check is fully duplicated and does nothing except setting wrong
variable LIYESCRYPT. Such variable was never used in the project.
Signed-off-by: Evgeny Grin (Karlson2k) <k2k@drgrin.dev>
When PAM is not used, login does not fork itself so its own PID should
be checked instead of parent PID.
Fixes: b44a6c316d96ab038492c63443156810670d176d (26-12-2007; "If started as init, login and sulogin need to start a new session.")
Signed-off-by: Evgeny Grin (Karlson2k) <k2k@drgrin.dev>
The correct utmp update functionality was broken mainly by commit
91fc51387ca5341e1a1f778a967886c5fe589cb8, which moved update of utmp
after forking (when PAM is used). It was also misinterpretation of
GNU/Linux utmp specifications, where is specified that ut_pid must be
the PID of the **login** process (not a PID of any forked process).
Wrong ut_pid also prevents utmp cleanup, which performed by init process
and should clean entry with the same ut_pid as started login process.
GNU/Linux description of utmp updates can be found at the next url:
https://man7.org/linux/man-pages/man5/utmp.5.html
Signed-off-by: Evgeny Grin (Karlson2k) <k2k@drgrin.dev>
When no "ut_id" is provided by previous utmp file entry, "login" must
generate its own "ut_id". Historically tty number was used for it.
However, if current device name is three characters or shorter, then
empty "ut_id" is produced or even garbage is copied from uninitialised
part of the "line".
This commit fixes it.
This patch uses unportable C extension Elvis operator as it is already
used everywhere in the code.
Signed-off-by: Evgeny Grin (Karlson2k) <k2k@drgrin.dev>
Linux seems to at least write one group always from getgroups(2).
However, POSIX doesn't guarantee this, and a system might have 0 groups.
It is implementation‐defined whether getgroups() also returns
the effective group ID in the grouplist array.
Considering such a system, the call getgroups(0,NULL) could indeed
return 0, and the second call to getgroups might return a higher value,
if the group list has grown in between (race condition). If this is the
case, we'd return an array of 0 elements (or 1, due to the MALLOC()
trick to avoid calling it with 0), with no elements filled, but where
ngids has been updated to have a positive value. When the caller of
agetgroups() reads the array, they'd overrun the buffer.
Fixes: 05322ed89a1c (2025-01-24; "lib/shadow/grp/: agetgroups(): Add function")
Fixes: de941a7601f8 (2025-01-24; "lib/, src/: Simplify allocation of buffer")
Signed-off-by: Alejandro Colomar <alx@kernel.org>
"config.h" is a locally generated header. It must be included as
'#include "config.h"'.
It is already included correctly in some sources files. This commit
unifies the way how "config.h" is included.
Signed-off-by: Evgeny Grin (Karlson2k) <k2k@drgrin.dev>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.