Skip to content

Conversation

@Karlson2k
Copy link
Contributor

This PR adds ability to use BOTH utmp and logind.
If both enabled, then for the number of active sessions logind used first, and utmp is used as a fallback. The same for "get_session_host": logind tried first and then utmp tried as a fallback.
Other utmp functionality enabled independently from logind.

This patch is needed because modern systemd (at least 256, 257) does not update utmp. Neither pad_systemd, nor logind does not write information to utmp.
This still breaks some software, including basic logname command.

With the patch utmp and logind can be enabled/disabled independently, allowing building a package that suits particular needs.
The only limitation is that utmp and logind cannot be simultaneously disabled (at least one option must be enabled).

The updated test has not been check for proper functioning on my machine.


count = active_sessions_count(name, limit);
#ifdef ENABLE_LOGIND
if (exceeded < 0)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this dead code? The condition is always true, because exceeded is -1, so you could do that unconditionally, right?

Comment on lines +514 to +515
extern int active_sessions_limit_exceeded_utmp(const char *name,
unsigned long limit);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is some alignment mistake here.

Comment on lines +541 to +542
extern int active_sessions_limit_exceeded_lgnd(const char *name,
unsigned long limit);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alignment. Please use spaces for alignment (tabs for indentation).

Comment on lines -512 to +542
extern unsigned long active_sessions_count(const char *name,
unsigned long limit);
extern int active_sessions_limit_exceeded_lgnd(const char *name,
unsigned long limit);
Copy link
Collaborator

@alejandro-colomar alejandro-colomar Jul 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this API set is becoming big and complex, it would be interesting to move it to its own header files, "lib/logind.h" and "lib/utmp.h".

Comment on lines -408 to +407
while ((ut = getutxent()))
while ((ut = getutxent()) && (count <= limit))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't add redundant parens (the existing ones are for allowing =).

Comment on lines -420 to -422
if (count > limit) {
break;
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this moved to the while condition? Is it necessary, or is it cosmetic? If the latter, please do it in a separate commit.


err = get_session_host(&host);
#ifdef ENABLE_LOGIND
if (0 != err)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dead code?

{
unsigned long limit, count;
unsigned long limit;
int exceeded = -1;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, don't initialize. Prefer assignment closer to use. Initialization of variables can hide logic bugs.

Comment on lines -139 to +147
if (count > limit) {
if (exceeded > 0) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if it's still -1? Is that possible?

}

unsigned long active_sessions_count(const char *name, MAYBE_UNUSED unsigned long limit)
int active_sessions_limit_exceeded_lgnd(const char *name, unsigned long limit)
Copy link
Collaborator

@alejandro-colomar alejandro-colomar Jul 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

exceeds, in present, is probably more conventional, no?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or I don't know. I'm not convinced by the function name, but I don't want to strongly oppose it if you want it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

English is not my native language, so I'm not very picky in English words. :)
I'm fine with renaming it to active_sessions_limit_exceeds_lgnd.
Probably it should be renamed to active_sessions_limit_ok_lgnd (with reversing the logic).
Select whatever is nice for you and I'll update the code.

Copy link
Collaborator

@alejandro-colomar alejandro-colomar Jul 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please change it to exceeds for now. I'm not sure about ok.

(I still don't fully understand this, so we may need to come back to this issue. Sorry.)

@ikerexxe
Copy link
Collaborator

I have significant concerns about this approach. As you've noted, this change could potentially break basic operating system software, and it appears to exacerbate the problem rather than mitigating it.

Currently, the established practice is to choose between utmp or logind for session management. When distributions decide to transition from one to the other, it typically involves a coordinated change in the build configuration. For example, in Fedora, a change of this magnitude would necessitate a Fedora System-Wide Change proposal to ensure proper communication and adaptation across the ecosystem. Other distributions likely have similar mechanisms.

While I'm not privy to the specific reasons behind systemd's shift away from updating utmp directly, I believe that the solution should involve proper communication and adaptation from systemd to other packages, rather than introducing a dual-system approach that could lead to further fragmentation and instability.

Introducing a scenario where both utmp and logind can be simultaneously enabled, with a fallback mechanism, seems to complicate the system and potentially lead to unexpected behavior and maintenance challenges down the line. The current "either/or" model, while perhaps requiring more effort for transitions, ensures a clearer and more predictable session management environment.

@alejandro-colomar
Copy link
Collaborator

Cc: @thesamesam

@Karlson2k
Copy link
Contributor Author

I have significant concerns about this approach. As you've noted, this change could potentially break basic operating system software, and it appears to exacerbate the problem rather than mitigating it.

Actually, the basic system software is already broken.
This approach allows to choose the way, how things are handled. It does not enforce to use both utmp and logind.

Currently, the established practice is to choose between utmp or logind for session management. When distributions decide to transition from one to the other, it typically involves a coordinated change in the build configuration. For example, in Fedora, a change of this magnitude would necessitate a Fedora System-Wide Change proposal to ensure proper communication and adaptation across the ecosystem. Other distributions likely have similar mechanisms.

And this will continue to work perfectly fine. Fedora still can use logind-only mode.

While I'm not privy to the specific reasons behind systemd's shift away from updating utmp directly, I believe that the solution should involve proper communication and adaptation from systemd to other packages, rather than introducing a dual-system approach that could lead to further fragmentation and instability.

I cannot see any instability, that can be introduced by this change.
For example, instead of silently accepting more logins than allowed by limit (as it currently done when number of logins cannot be acquired from systemd), a fallback path is used.

This PR can be extended with --enable-utmp=update-only mode, which could be enabled only together with systemd. In such mode utmp could be only updated, but not used as a fallback.

However, I'm sure that fallback is better than nothing when systemd fails.

Introducing a scenario where both utmp and logind can be simultaneously enabled, with a fallback mechanism, seems to complicate the system and potentially lead to unexpected behavior and maintenance challenges down the line. The current "either/or" model, while perhaps requiring more effort for transitions, ensures a clearer and more predictable session management environment.

This situation is already broken and must be fixed now.
For example, on Gentoo with current stable systemd (sys-apps/systemd-257.6) console sessions are incorrect: any software relays on logname command or getlogin() function is not working properly (while the same software in terminal emulators under KDE is fine). The output is always literally LOGIN instead of the name of the actual user. (@thesamesam I decided not to open a Gentoo bug as it is a clear upstream problem).
coreutls (for logname command) will not fix this problem:
https://github.com/coreutils/coreutils/blob/8f9fc8f08c10c3b097211f95c6354a85d41f1101/src/logname.c#L72-L74

Glibc uses audit first (disabled on many distributions and has global performance penalty) and then utmp as a fallback:
https://github.com/bminor/glibc/blob/d6c2760ef7f7cdeab912767f04db4b14632fbb5f/sysdeps/unix/sysv/linux/getlogin.c#L34-L38
This is a getlogin_fd0 () implementation:
https://github.com/bminor/glibc/blob/d6c2760ef7f7cdeab912767f04db4b14632fbb5f/sysdeps/unix/getlogin.c

Probably glibc will never be fixed:
https://github.com/thkukuk/utmpx/blob/main/Y2038.md#glibc

In short:

This looks inconsistent (utmp is updated before firing login binary, but not by the login binary, neither during login process) and the best solution is to add build-time option for utmp manipulation, like suggested in this PR.
I'd emphasise: this build options does not enforce utmp updates for these users who do not need it.

When other software will be fixed, or utmp is completely eliminated, or when one does not want utmp updates, support for utmp in shadow can be easily disabled at build-time

@Karlson2k
Copy link
Contributor Author

@thesamesam PR #1282 is needed to complete the fix for Gentoo.
See also details in the comment #1282 (comment) (when built without logind).

@alejandro-colomar
Copy link
Collaborator

@thesamesam PR #1282 is needed to complete the fix for Gentoo. See also details in the comment #1282 (comment) (when built without logind).

Is there a Gentoo bug ticket? Could you please link to it?

@ikerexxe
Copy link
Collaborator

Actually, the basic system software is already broken. This approach allows to choose the way, how things are handled. It does not enforce to use both utmp and logind.

I must have misunderstood the PR because I understood that the fallback was going to be forced. Since you are making it configurable I see it as fine.

Probably glibc will never be fixed: https://github.com/thkukuk/utmpx/blob/main/Y2038.md#glibc

From my conversations with their developers it's not going to be fixed, so we will all have to migrate to logind (or some other mechanism) sooner rather than later.

@thesamesam
Copy link
Contributor

(Just saying that I've seen the discussion(s) and I will look properly, but I can't look just yet and it's not the kind of thing I can give a quick take on. Thank you for the ping!)

count = sd_uid_get_sessions(pw->pw_uid, 0, NULL);

return count;
return (count > limit) ? 1 : 0;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indentation issue

/***********************
* TEST
**********************/
static void test_active_sessions_count_return_ok(void **state)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you are changing the meaning of the test I'd also change the name of the function.

Comment on lines +80 to +83
cmocka_unit_test(\
test_active_sessions_limit_exceeded_lgnd_return_exceeded),
cmocka_unit_test(\
test_active_sessions_limit_exceeded_lgnd_prefix_failure),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's keep this in the same line

Copy link
Contributor Author

@Karlson2k Karlson2k Jul 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The line becomes longer then 80 chars.
If it is not a problem, I'll move back to the same line.

Copy link
Collaborator

@alejandro-colomar alejandro-colomar Jul 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, I prefer to avoid surpassing the right margin, but in this case, let's keep it in one line. Tests are special, anyway.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, let's keep it in the same line

unsigned long
active_sessions_count(const char *name, unsigned long limit)
int
active_sessions_limit_exceeded_utmp(const char *name, unsigned long limit)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function doesn't return -1 on error paths like setutxent() or getutxent() failures. Currently, if setutxent() fails, it will just iterate through 0 entries and return 0 (not exceeded). If getutxent() fails to return anything, it also returns 0. This means utmp might silently fail to check the limit and incorrectly report "not exceeded" if there's an issue with utmp file access.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, good point.
I'll update the code.

@Karlson2k
Copy link
Contributor Author

@alejandro-colomar Before further updating this PR, let's finish #1292 first, as this PR should be used on top.

@alejandro-colomar
Copy link
Collaborator

This needs to be rebased.

@alejandro-colomar
Copy link
Collaborator

This would need some rebasing.

@Karlson2k
Copy link
Contributor Author

I'll take care about it soon or shortly after the New Year.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants