I only did some ad-hoc testing with the only 2 programs that both read and write to utmp and that I have integrated with utmps: util-linux login and OpenSSH. And I used the simple tests I attached earlier. All good.
Cool, thanks. I'll still give it some more thought. The fact that my earlier modification is broken is exactly why I didn't do it in the first place, and I'm an idiot for having changed it without thinking, and that's what happens when I'm looking at those things during the week-end while doing something else. :P So now I'm going to think it through and find the correct way of implementing that change. It may be your patch; it may be different. And let me mention once more that I hate vague specifications that sound simple but have hidden complexity like this. I will also use the opportunity to understand what's going on with the ut_id field.
Now that that's done, I'm having second-thoughts about this whole utmp/wtmp endeavor and wondering if it's worth the efforts. Don't get me wrong, I think your implementation fulfills its premises of security and robustness quite well, and I like how it fits within the s6 "ecosystem". But the POSIX API and data structures feel clunky and archaic. Take for example the id field, which is an arbitrary 4-character string used to uniquely identify an entry in the database. That doesn't strike me as very robust nor secure, given that there is no mechanism to prevent id collisions.
Well yes, it's not a secret that utmp sucks.
Rich Felker may have made the right choice in leaving it on the cutting floor and expecting that no-one would miss it. Perhaps we should just let it die.
Users want 'who' to work. musl-based distributions can't make 'who' work. Users blame the lack of 'who' on musl and stop using musl-based distributions. Having a working utmp implementation makes users happy and helps with musl adoption. The reason why Rich didn't implement utmp in musl is not that the API and data structures are bad. There is *plenty* of suckage in the POSIX standard - starting with something everyone uses: stdio! - and he happily implemented 99% of it. The reason is that utmp is not implementable in a libc without requiring suid/sgid binaries to modify the database, see https://wiki.musl-libc.org/faq.html#Q:-Why-is-the-utmp/wtmp-functionality-only-implemented-as-stubs? So it's not "the APIs suck", it's "it's a security risk". utmps is the only existing *secure* utmp implementation, because it relies on daemons and kernel-verified client credentials to actually access the database, and removes the need for suid/sgid. The "needs daemons to work securely" part is why it can't be done inside of a libc; you could consider utmps as a companion package to musl for a complete implementation of the standard.
Isn't there a modern framework equivalent for user accounting on *nix-like systems? I mean beside systemd of course :)
I have exactly zero doubt that any attempt at designing a "modern" framework for user accounting would manage to do worse than utmp. systemd has done exactly that. Other attempts would be similar. People who would actually take time and energy to do this right are not interested in doing it, because user accounting is 1. ultimately user snooping, and 2. becoming useless by the day with the way Unix is used now. As you said, it's best to let it die - not because utmp is bad, but because *the concept of user accounting* is bad. I'm just providing a utmp implementation that is as secure as possible for existing programs that use it, because people want those programs to work; but if you like user accounting, then you'll have to deal with all the flaws of utmp. :P -- Laurent