lib/utmp.c: Fix use of last utmp entry instead of patrial-match entry
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.
src/chfn.c: Do not allow the 'slop' fields to appear before any non-slop gecos fields
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).
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.
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.
configure.ac: Make sure that logind is enabled if requested, make --enable-logind default
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.
The code does not enabled logind unconditionally by default. Instead
configure checks for logind (libsystemd) availability and enables it
only if found.
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".
[[]] 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.
configure: Move AC_ARG_ENABLE. It cannot be conditional.
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.
AM_CONDITIONAL() must not be used in shell's if branches. Instead it
must be specified one time only (per conditional variable) with test
"something" as a second parameter.
See https://www.gnu.org/software/automake/manual/html_node/Usage-of-Conditionals.html#index-AM_005fCONDITIONAL-2
configure: Remove duplicated check and unused Makefile substitution
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.
src/login.c: Fix checking whether 'login' is started as 'init'
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
lib/utmp.c: Align generated "ut_id" with modern software
Modern software (systemd, utemper) usually use full "ut_line" as "ut_id"
if string is up to four chars or last four chars if "ut_line" is longer.
For reference:
* libutemper (used by many graphical terminal emulator applications
(konsole, xterm, others) to deal with utmp file):
https://github.com/altlinux/libutempter/blob/4caa8ab94ff8b207228fa723a89214bf5e929321/libutempter/utempter.c#L99-L103
* systemd:
uses full name of the device:
https://github.com/systemd/systemd/blob/8013beb4a2221680b2c741bac6b3a33fe66406e1/units/getty%40.service.in#L41-L44
or **last** four characters:
https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html#UtmpIdentifier=
The code in the commit is optimised for visual C code size.
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.
lib/shadow/grp/: agetgroups(): Fix possible buffer overrun on non-Linux systems
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.
"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.
This API set implements another usual loop around strsep(3).
This one implements a loop where we are interested in an arbitrary
number of fields. For that, a NULL terminator is added at the end.
That is commonly referred to as "list".
This API set implements the usual loop around strsep(3).
This one implements a loop where we are interested in an exact number of
fields. I'll add another API set, strsep2ls() and STRSEP2LS(), which
will add a NULL terminator, for arbitrary numbers of fields.
These functions are just like [v]asprintf(3), but simpler.
They return the newly allocated memory, which allows us to use the
[[gnu::malloc(free)]] attribute, which enhances static analysis.
They also omit the length, which we don't care about at all.
As a curiosity, Plan9 seems to provide this same API, under the name
smprint(3).
autogen.sh, lib/: Replace must_be_array() by -Werror=sizeof-pointer-div
The error works as well as the magic macro, and we get cleaner code.
Plus, very soon we'll get the countof() operator from GCC 16 and
Clang 21, which doesn't even need this diagnostic to work safely.