Hi Juan,
On Thu, Sep 03, 2026 at 02:59:09PM +0000, Juan Muñoz wrote:
1. A single counter does not survive sub-ranges
The naive reading of "store the last uid and increment from there" breaks when
a range is requested explicitly:
# REUSE_IDS=no
adduser --firstuid 5000 --lastuid 5010 rhigh # gets 5000, counter=5000
addgroup --firstgid 2090 --lastgid 2093 rlow
warn: No GID is available in the range 5001-2093 (FIRST_GID - LAST_GID)
fatal: The group `rlow' was not created.
The 2090-2093 range is completely empty, but the counter of the default range
pushed the floor above its ceiling.
My fix is to make the range part of the state file key, so each range carries
its own counter:
@global:last_id_1000_59999=1006:last_sys_id_100_999=104
The guarantee becomes "an id is not handed out twice within the range it came
from". Does that match what you had in mind, or would you rather have a single
counter with a different rule for sub-ranges?
I would say "if a range is explicitly requested, that overrides
everything and the accounts gets the first free uid in that range
without state being updated".
That would also help to keep the state file small.
2. Should an explicit range turn off the automatism?
You wrote that for --uid "the wish of the local admin wins and turns off the
automatism". Asking for --firstuid/--lastuid looks like the same kind of explicit
wish to me, and treating it that way would also leave firstlastuidgid.t untouched. But it
does mean that an admin who always carves ranges never gets the guarantee. Your call.
Yes, it should turm off the automatism.
3. The default is more expensive than it looks
With the counter always on, 122 assertions fail in firstlastuidgid.t,
firstlastuidgid_orig.t, uidgidpool.t and suidsgidpool.t. They are not stale:
they encode the current contract, that adduser picks the first free id of the
range. After any deletion that stops being true.
So I currently default REUSE_IDS to yes, which leaves every existing
installation and the whole test suite untouched, and lets an admin opt in.
Flipping it to no is a one-word change plus a NEWS.Debian entry, but it needs
those tests adapted. Which do you prefer?
I would offer to adapt the tests to save you from that tedious work. I
think that's worth it.
I did not want to rewrite assertions in firstlastuidgid*.t anyway, since you
are reworking that file in wip/new-firstlastuidgid.
That rework is done, I am fine with the -old file going away now instead
of spending an hour fixing it. The new test was vibecoded and I kept the
old one around to be sure. I think I am now confident enough that the
new test is fine.
4. Where should the counter live inside the state file?
The store is keyed by user name and a counter belongs to no user. Rather than
storing it under a fake user name, I taught _read_state() and _write_state()
about a reserved '@global' record, so delete_state_user() can not take the
counters with it. That touches the format of your module, so tell me if you
prefer something else.
@global, _adduser, _adduser-internal, _internal or any other string that
doesn't constitute a valid user name is fine.
5. Is a second knob wanted at all?
You never mentioned configuration, so this may be over-engineering on my side:
I added ID_COUNTER_INIT=first_free|highest, because starting at the first free
id (as you suggested) cannot cover accounts that were deleted before the state
file existed, which was Aaron Hall's unanswered question from 2006. If you
would rather not have that option, I will drop it.
I like a gold plate on code, so if it's already there, go ahead. It's a
bit ugly that we now have a config option that is only used once on
adduser's first run.
Unrelated to this bug, I also came across a couple of small things while
reading the code (a duplicated exit code value that contradicts the manpage,
among others). I will file those separately rather than mixing them in here.
Yes, please.
Greetings
Marc
--
-----------------------------------------------------------------------------
Marc Haber | "I don't trust Computers. They | Mailadresse im Header
Leimen, Germany | lose things." Winona Ryder | Fon: *49 6224 1600402
Nordisch by Nature | How to make an American Quilt | Fax: *49 6224 1600421