pax_global_header 0000666 0000000 0000000 00000000064 14314710576 0014522 g ustar 00root root 0000000 0000000 52 comment=a12528f055292b0634de829bc51608a9e1679d2a
cromerc-opensysusers-a12528f/ 0000775 0000000 0000000 00000000000 14314710576 0016266 5 ustar 00root root 0000000 0000000 cromerc-opensysusers-a12528f/.gitignore 0000664 0000000 0000000 00000000142 14314710576 0020253 0 ustar 00root root 0000000 0000000 /man/*.1
/man/*.5
/man/*.8
/man/*.html
/bin/sysusers
/bin/opensysusers
/openrc/opensysusers.initd
cromerc-opensysusers-a12528f/LICENSE 0000664 0000000 0000000 00000002477 14314710576 0017305 0 ustar 00root root 0000000 0000000 Copyright (c) 2017 - 2018, Chris Cromer
Copyright (c) 2012, Gentoo Foundation
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
cromerc-opensysusers-a12528f/Makefile 0000664 0000000 0000000 00000005763 14314710576 0017741 0 ustar 00root root 0000000 0000000 SYSCONFDIR = /etc
PREFIX ?= /usr/local
BINDIR = $(PREFIX)/bin
LIBDIR = $(PREFIX)/lib
MANDIR = $(PREFIX)/share/man
DOCDIR = $(PREFIX)/share/doc/opensysusers
TESTDIR = /run/sysusers.d
BINMODE = 0755
MODE = 0644
INSTALL = install
MAKE = make
HAVESYSTEMD = yes
HAVEOPENRC = no
HAVEMAN = yes
HAVEDOC = no
INITD = opensysusers.initd
BASIC = basic.conf
ifeq ($(HAVESYSTEMD),yes)
BINNAME = sysusers
else
BINNAME = opensysusers
endif
TESTFILES = $(wildcard test/*.conf)
all: sysusers
ifeq ($(HAVEOPENRC),yes)
all: $(INITD)
endif
ifeq ($(HAVEMAN),yes)
all:
+$(MAKE) HAVEDOC=$(HAVEDOC) INSTALL=$(INSTALL) DOCMODE=$(MODE) MANDIR=$(MANDIR) DOCDIR=$(DOCDIR) DESTDIR=$(DESTDIR) -C man
endif
EDIT = sed "s|@BINNAME[@]|$(BINNAME)|"
RM = rm -f
CHMOD = chmod $(BINMODE)
opensysusers: sysusers
$(INSTALL) $< $@
$(INITD): $(INITD).in
@echo "GEN $@"
@$(RM) "$@"
@$(EDIT) $< >"$@"
@$(CHMOD) "$@"
clean-openrc:
$(RM) $(INITD)
clean-man:
+$(MAKE) INSTALL=$(INSTALL) DOCMODE=$(MODE) MANDIR=$(MANDIR) DOCDIR=$(DOCDIR) DESTDIR=$(DESTDIR) -C man clean
clean: clean-bin
ifeq ($(HAVEOPENRC),yes)
clean: clean-openrc
endif
ifeq ($(HAVEMAN),yes)
clean: clean-man
endif
install-shared:
$(INSTALL) -Dm $(MODE) $(BASIC) $(DESTDIR)$(LIBDIR)/sysusers.d/$(BASIC)
install-default-bin: sysusers
$(INSTALL) -Dm $(BINMODE) sysusers $(DESTDIR)$(BINDIR)/$(BINNAME)
install-custom-bin: sysusers
$(INSTALL) -Dm $(BINMODE) sysusers $(DESTDIR)$(BINDIR)/$(BINNAME)
install-openrc: $(INITD)
$(INSTALL) -Dm $(BINMODE) $(INITD) $(DESTDIR)$(SYSCONFDIR)/init.d/opensysusers
install-man:
+$(MAKE) INSTALL=$(INSTALL) DOCMODE=$(MODE) MANDIR=$(MANDIR) DOCDIR=$(DOCDIR) DESTDIR=$(DESTDIR) -C man install
install-tests:
$(INSTALL) -Dm $(MODE) $(TESTFILES) $(DESTDIR)$(TESTDIR)/
uninstall-shared:
$(RM) $(DESTDIR)$(LIBDIR)/sysusers.d/$(BASIC)
uninstall-default-bin:
$(RM) $(DESTDIR)$(BINDIR)/$(BINNAME)
uninstall-custom-bin:
$(RM) $(DESTDIR)$(BINDIR)/$(BINNAME)
uninstall-openrc:
$(RM) $(DESTDIR)$(SYSCONFDIR)/init.d/opensysusers
uninstall-man:
+$(MAKE) INSTALL=$(INSTALL) DOCMODE=$(MODE) MANDIR=$(MANDIR) DOCDIR=$(DOCDIR) DESTDIR=$(DESTDIR) -C man uninstall
ifeq ($(HAVESYSTEMD),yes)
install: install-shared
uninstall: uninstall-shared
ifeq ($(HAVEMAN),yes)
install: install-man
uninstall: uninstall-man
endif
ifeq ($(BINNAME),sysusers)
install: install-default-bin
uninstall: uninstall-default-bin
else
install: install-custom-bin
uninstall: uninstall-custom-bin
endif
ifeq ($(HAVEOPENRC),yes)
install: install-openrc
uninstall: uninstall-openrc
endif
else
install: install-shared install-default-bin
uninstall: uninstall-shared uninstall-default-bin
ifeq ($(HAVEMAN),yes)
install: install-man
uninstall: uninstall-man
endif
ifeq ($(HAVEOPENRC),yes)
install: install-openrc
uninstall: uninstall-openrc
endif
endif
.PHONY: all install install-custom-bin install-default-bin install-man install-openrc install-shared install-tests uninstall uninstall-custom-bin uninstall-default-bin uninstall-man uninstall-openrc uninstall-shared clean clean-bin clean-man clean-openrc
cromerc-opensysusers-a12528f/README.md 0000664 0000000 0000000 00000001214 14314710576 0017543 0 ustar 00root root 0000000 0000000 This is a utility written to process sysusers.d files so that they can be handled on systems with or without systemd installed.
For more information on the files this utility can process, see the
sysusers.d man page [1].
For more information on the systemd-sysuser command, see the
systemd-sysuers man page [2].
If built with the make flag SYSTEMDCOMPAT=FALSE, it will only install the basic script to process sysusers.d conf files. Otherwise it installs a script that imitates systemd-sysusers command.
[1] https://www.freedesktop.org/software/systemd/man/sysusers.d.html
[2] https://www.freedesktop.org/software/systemd/man/systemd-sysusers.html cromerc-opensysusers-a12528f/basic.conf 0000664 0000000 0000000 00000002160 14314710576 0020215 0 ustar 00root root 0000000 0000000 # This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
# The superuser
u root 0 "Super User" /root
# The nobody user for NFS file systems
u nobody 65534 "Nobody" -
# Administrator group: can *see* more than normal users
g adm - - -
# Administrator group: can *do* more than normal users
g wheel - - -
# Access to certain kernel and userspace facilities
g kmem - - -
g tty 5 - -
g utmp - - -
# Hardware access groups
g audio - - -
g disk - - -
g input - - -
g kvm - - -
g lp - - -
g optical - - -
g render - - -
g storage - - -
g uucp - - -
g video - - -
# Default group for normal users
g users - - -
cromerc-opensysusers-a12528f/man/ 0000775 0000000 0000000 00000000000 14314710576 0017041 5 ustar 00root root 0000000 0000000 cromerc-opensysusers-a12528f/man/Makefile 0000664 0000000 0000000 00000005024 14314710576 0020502 0 ustar 00root root 0000000 0000000 manfiles5 = sysusers.d.5
manfiles8 = systemd-sysusers.8 systemd-sysusers.service.8
docfiles = UIDS-GIDS.html USER_NAMES.html
xsltargs = --nonet \
--xinclude \
--maxdepth 9000 \
--stringparam man.output.quietly 1 \
--stringparam funcsysnopsis.style ansi \
--stringparam man.authors.section.enabled 0 \
--stringparam man.copyright.section.enabled 0 \
--stringparam systemd.version 238.51
all: man
ifeq ($(HAVEDOC),yes)
all: doc
endif
man:
xsltproc $(xsltargs) custom-man.xsl systemd-sysusers.xml
xsltproc $(xsltargs) custom-man.xsl sysusers.d.xml
doc:
if command -v cmark-gfm; then \
md='cmark-gfm --extension table'; \
elif command -v cmark; then \
md='cmark'; \
else \
md='markdown'; \
fi; \
$$md UIDS-GIDS.md > UIDS-GIDS.html; \
$$md USER_NAMES.md > USER_NAMES.html
# Delete files because wget can't overwrite them
download-docs:
rm -f *.xml *.xsl
if command -v wget; then \
download='wget'; \
elif command -v curl; then \
download='curl --location --remote-name-all'; \
elif command -v fetch; then \
download='fetch'; \
fi; \
$$download \
'https://github.com/systemd/systemd/raw/main/man/custom-html.xsl' \
'https://github.com/systemd/systemd/raw/main/man/custom-man.xsl' \
'https://github.com/systemd/systemd/raw/main/man/standard-options.xml' \
'https://github.com/systemd/systemd/raw/main/man/standard-specifiers.xml' \
'https://github.com/systemd/systemd/raw/main/man/systemd-sysusers.xml' \
'https://github.com/systemd/systemd/raw/main/man/sysusers.d.xml' \
'https://github.com/systemd/systemd/raw/main/docs/UIDS-GIDS.md' \
'https://github.com/systemd/systemd/raw/main/docs/USER_NAMES.md'
clean:
rm -f $(manfiles5)
rm -f $(manfiles8)
rm -f $(docfiles)
install-man:
$(INSTALL) -d $(DESTDIR)$(MANDIR)/man5 $(DESTDIR)$(MANDIR)/man8
$(INSTALL) -m $(DOCMODE) $(manfiles5) $(DESTDIR)$(MANDIR)/man5
$(INSTALL) -m $(DOCMODE) $(manfiles8) $(DESTDIR)$(MANDIR)/man8
install-doc:
$(INSTALL) -d $(DESTDIR)$(DOCDIR)
$(INSTALL) -m $(DOCMODE) $(docfiles) $(DESTDIR)$(DOCDIR)
install: install-man
ifeq ($(HAVEDOC),yes)
install: install-doc
endif
uninstall-man:
for man in ${manfiles5}; do rm -f $(DESTDIR)$(MANDIR)/man5/$$man; done
for man in ${manfiles8}; do rm -f $(DESTDIR)$(MANDIR)/man8/$$man; done
uninstall-doc:
for doc in ${docfiles}; do rm -f $(DESTDIR)$(DOCDIR)/$$doc; done
rm -rf --one-file-system $(DESTDIR)$(DOCDIR)
uninstall: uninstall-man
ifeq ($(HAVEDOC),yes)
uninstall: uninstall-doc
endif
.PHONY: all man doc download-docs clean install install-man install-doc uninstall-man uninstall-doc uninstall
cromerc-opensysusers-a12528f/man/UIDS-GIDS.md 0000664 0000000 0000000 00000045065 14314710576 0020665 0 ustar 00root root 0000000 0000000 ---
title: Users, Groups, UIDs and GIDs on systemd Systems
category: Users, Groups and Home Directories
layout: default
SPDX-License-Identifier: LGPL-2.1-or-later
---
# Users, Groups, UIDs and GIDs on systemd Systems
Here's a summary of the requirements `systemd` (and Linux) make on UID/GID
assignments and their ranges.
Note that while in theory UIDs and GIDs are orthogonal concepts they really
aren't IRL. With that in mind, when we discuss UIDs below it should be assumed
that whatever we say about UIDs applies to GIDs in mostly the same way, and all
the special assignments and ranges for UIDs always have mostly the same
validity for GIDs too.
## Special Linux UIDs
In theory, the range of the C type `uid_t` is 32bit wide on Linux,
i.e. 0…4294967295. However, four UIDs are special on Linux:
1. 0 → The `root` super-user
2. 65534 → The `nobody` UID, also called the "overflow" UID or similar. It's
where various subsystems map unmappable users to, for example file systems
only supporting 16bit UIDs, NFS or user namespacing. (The latter can be
changed with a sysctl during runtime, but that's not supported on
`systemd`. If you do change it you void your warranty.) Because Fedora is a
bit confused the `nobody` user is called `nfsnobody` there (and they have a
different `nobody` user at UID 99). I hope this will be corrected eventually
though. (Also, some distributions call the `nobody` group `nogroup`. I wish
they didn't.)
3. 4294967295, aka "32bit `(uid_t) -1`" → This UID is not a valid user ID, as
`setresuid()`, `chown()` and friends treat -1 as a special request to not
change the UID of the process/file. This UID is hence not available for
assignment to users in the user database.
4. 65535, aka "16bit `(uid_t) -1`" → Before Linux kernel 2.4 `uid_t` used to be
16bit, and programs compiled for that would hence assume that `(uid_t) -1`
is 65535. This UID is hence not usable either.
The `nss-systemd` glibc NSS module will synthesize user database records for
the UIDs 0 and 65534 if the system user database doesn't list them. This means
that any system where this module is enabled works to some minimal level
without `/etc/passwd`.
## Special Distribution UID ranges
Distributions generally split the available UID range in two:
1. 1…999 → System users. These are users that do not map to actual "human"
users, but are used as security identities for system daemons, to implement
privilege separation and run system daemons with minimal privileges.
2. 1000…65533 and 65536…4294967294 → Everything else, i.e. regular (human) users.
Note that most distributions allow changing the boundary between system and
regular users, even during runtime as user configuration. Moreover, some older
systems placed the boundary at 499/500, or even 99/100. In `systemd`, the
boundary is configurable only during compilation time, as this should be a
decision for distribution builders, not for users. Moreover, we strongly
discourage downstreams to change the boundary from the upstream default of
999/1000.
Also note that programs such as `adduser` tend to allocate from a subset of the
available regular user range only, usually 1000..60000. And it's also usually
user-configurable, too.
Note that systemd requires that system users and groups are resolvable without
networking available — a requirement that is not made for regular users. This
means regular users may be stored in remote LDAP or NIS databases, but system
users may not (except when there's a consistent local cache kept, that is
available during earliest boot, including in the initial RAM disk).
## Special `systemd` GIDs
`systemd` defines no special UIDs beyond what Linux already defines (see
above). However, it does define some special group/GID assignments, which are
primarily used for `systemd-udevd`'s device management. The precise list of the
currently defined groups is found in this `sysusers.d` snippet:
[basic.conf](https://raw.githubusercontent.com/systemd/systemd/main/sysusers.d/basic.conf.in)
It's strongly recommended that downstream distributions include these groups in
their default group databases.
Note that the actual GID numbers assigned to these groups do not have to be
constant beyond a specific system. There's one exception however: the `tty`
group must have the GID 5. That's because it must be encoded in the `devpts`
mount parameters during earliest boot, at a time where NSS lookups are not
possible. (Note that the actual GID can be changed during `systemd` build time,
but downstreams are strongly advised against doing that.)
## Special `systemd` UID ranges
`systemd` defines a number of special UID ranges:
1. 60001…60513 → UIDs for home directories managed by
[`systemd-homed.service(8)`](https://www.freedesktop.org/software/systemd/man/systemd-homed.service.html). UIDs
from this range are automatically assigned to any home directory discovered,
and persisted locally on first login. On different systems the same user
might get different UIDs assigned in case of conflict, though it is
attempted to make UID assignments stable, by deriving them from a hash of
the user name.
2. 61184…65519 → UIDs for dynamic users are allocated from this range (see the
`DynamicUser=` documentation in
[`systemd.exec(5)`](https://www.freedesktop.org/software/systemd/man/systemd.exec.html)). This
range has been chosen so that it is below the 16bit boundary (i.e. below
65535), in order to provide compatibility with container environments that
assign a 64K range of UIDs to containers using user namespacing. This range
is above the 60000 boundary, so that its allocations are unlikely to be
affected by `adduser` allocations (see above). And we leave some room
upwards for other purposes. (And if you wonder why precisely these numbers:
if you write them in hexadecimal, they might make more sense: 0xEF00 and
0xFFEF). The `nss-systemd` module will synthesize user records implicitly
for all currently allocated dynamic users from this range. Thus, NSS-based
user record resolving works correctly without those users being in
`/etc/passwd`.
3. 524288…1879048191 → UID range for `systemd-nspawn`'s automatic allocation of
per-container UID ranges. When the `--private-users=pick` switch is used (or
`-U`) then it will automatically find a so far unused 16bit subrange of this
range and assign it to the container. The range is picked so that the upper
16bit of the 32bit UIDs are constant for all users of the container, while
the lower 16bit directly encode the 65536 UIDs assigned to the
container. This mode of allocation means that the upper 16bit of any UID
assigned to a container are kind of a "container ID", while the lower 16bit
directly expose the container's own UID numbers. If you wonder why precisely
these numbers, consider them in hexadecimal: 0x00080000…0x6FFFFFFF. This
range is above the 16bit boundary. Moreover it's below the 31bit boundary,
as some broken code (specifically: the kernel's `devpts` file system)
erroneously considers UIDs signed integers, and hence can't deal with values
above 2^31. The `systemd-machined.service` service will synthesize user
database records for all UIDs assigned to a running container from this
range.
Note for both allocation ranges: when an UID allocation takes place NSS is
checked for collisions first, and a different UID is picked if an entry is
found. Thus, the user database is used as synchronization mechanism to ensure
exclusive ownership of UIDs and UID ranges. To ensure compatibility with other
subsystems allocating from the same ranges it is hence essential that they
ensure that whatever they pick shows up in the user/group databases, either by
providing an NSS module, or by adding entries directly to `/etc/passwd` and
`/etc/group`. For performance reasons, do note that `systemd-nspawn` will only
do an NSS check for the first UID of the range it allocates, not all 65536 of
them. Also note that while the allocation logic is operating, the glibc
`lckpwdf()` user database lock is taken, in order to make this logic race-free.
## Figuring out the system's UID boundaries
The most important boundaries of the local system may be queried with
`pkg-config`:
```
$ pkg-config --variable=systemuidmax systemd
999
$ pkg-config --variable=dynamicuidmin systemd
61184
$ pkg-config --variable=dynamicuidmax systemd
65519
$ pkg-config --variable=containeruidbasemin systemd
524288
$ pkg-config --variable=containeruidbasemax systemd
1878982656
```
(Note that the latter encodes the maximum UID *base* `systemd-nspawn` might
pick — given that 64K UIDs are assigned to each container according to this
allocation logic, the maximum UID used for this range is hence
1878982656+65535=1879048191.)
Systemd has compile-time default for these boundaries. Using those defaults is
recommended. It will nevertheless query `/etc/login.defs` at runtime, when
compiled with `-Dcompat-mutable-uid-boundaries=true` and that file is present.
Support for this is considered only a compatibility feature and should not be
used except when upgrading systems which were created with different defaults.
## Considerations for container managers
If you hack on a container manager, and wonder how and how many UIDs best to
assign to your containers, here are a few recommendations:
1. Definitely, don't assign less than 65536 UIDs/GIDs. After all the `nobody`
user has magic properties, and hence should be available in your container, and
given that it's assigned the UID 65534, you should really cover the full 16bit
range in your container. Note that systemd will — as mentioned — synthesize
user records for the `nobody` user, and assumes its availability in various
other parts of its codebase, too, hence assigning fewer users means you lose
compatibility with running systemd code inside your container. And most likely
other packages make similar restrictions.
2. While it's fine to assign more than 65536 UIDs/GIDs to a container, there's
most likely not much value in doing so, as Linux distributions won't use the
higher ranges by default (as mentioned neither `adduser` nor `systemd`'s
dynamic user concept allocate from above the 16bit range). Unless you actively
care for nested containers, it's hence probably a good idea to allocate exactly
65536 UIDs per container, and neither less nor more. A pretty side-effect is
that by doing so, you expose the same number of UIDs per container as Linux 2.2
supported for the whole system, back in the days.
3. Consider allocating UID ranges for containers so that the first UID you
assign has the lower 16bits all set to zero. That way, the upper 16bits become
a container ID of some kind, while the lower 16bits directly encode the
internal container UID. This is the way `systemd-nspawn` allocates UID ranges
(see above). Following this allocation logic ensures best compatibility with
`systemd-nspawn` and all other container managers following the scheme, as it
is sufficient then to check NSS for the first UID you pick regarding conflicts,
as that's what they do, too. Moreover, it makes `chown()`ing container file
system trees nicely robust to interruptions: as the external UID encodes the
internal UID in a fixed way, it's very easy to adjust the container's base UID
without the need to know the original base UID: to change the container base,
just mask away the upper 16bit, and insert the upper 16bit of the new container
base instead. Here are the easy conversions to derive the internal UID, the
external UID, and the container base UID from each other:
```
INTERNAL_UID = EXTERNAL_UID & 0x0000FFFF
CONTAINER_BASE_UID = EXTERNAL_UID & 0xFFFF0000
EXTERNAL_UID = INTERNAL_UID | CONTAINER_BASE_UID
```
4. When picking a UID range for containers, make sure to check NSS first, with
a simple `getpwuid()` call: if there's already a user record for the first UID
you want to pick, then it's already in use: pick a different one. Wrap that
call in a `lckpwdf()` + `ulckpwdf()` pair, to make allocation
race-free. Provide an NSS module that makes all UIDs you end up taking show up
in the user database, and make sure that the NSS module returns up-to-date
information before you release the lock, so that other system components can
safely use the NSS user database as allocation check, too. Note that if you
follow this scheme no changes to `/etc/passwd` need to be made, thus minimizing
the artifacts the container manager persistently leaves in the system.
5. `systemd-homed` by default mounts the home directories it manages with UID
mapping applied. It will map four UID ranges into that uidmap, and leave
everything else unmapped: the range from 0…60000, the user's own UID, the range
60514…65534, and the container range 524288…1879048191. This means
files/directories in home directories managed by `systemd-homed` cannot be
owned by UIDs/GIDs outside of these four ranges (attempts to `chown()` files to
UIDs outside of these ranges will fail). Thus, if container trees are to be
placed within a home directory managed by `systemd-homed` they should take
these ranges into consideration and either place the trees at base UID 0 (and
then map them to a higher UID range for use in user namespacing via another
level of UID mapped mounts, at *runtime*) or at a base UID from the container
UID range. That said, placing container trees (and in fact any
files/directories not owned by the home directory's user) in home directories
is generally a questionable idea (regardless of whether `systemd-homed` is used
or not), given this typically breaks quota assumptions, makes it impossible for
users to properly manage all files in their own home directory due to
permission problems, introduces security issues around SETUID and severely
restricts compatibility with networked home directories. Typically, it's a much
better idea to place container images outside of the home directory,
i.e. somewhere below `/var/` or similar.
## Summary
| UID/GID | Purpose | Defined By | Listed in |
|-----------------------|-----------------------|---------------|-------------------------------|
| 0 | `root` user | Linux | `/etc/passwd` + `nss-systemd` |
| 1…4 | System users | Distributions | `/etc/passwd` |
| 5 | `tty` group | `systemd` | `/etc/passwd` |
| 6…999 | System users | Distributions | `/etc/passwd` |
| 1000…60000 | Regular users | Distributions | `/etc/passwd` + LDAP/NIS/… |
| 60001…60513 | Human users (homed) | `systemd` | `nss-systemd` |
| 60514…60577 | Host users mapped into containers | `systemd` | `systemd-nspawn` |
| 60578…61183 | Unused | | |
| 61184…65519 | Dynamic service users | `systemd` | `nss-systemd` |
| 65520…65533 | Unused | | |
| 65534 | `nobody` user | Linux | `/etc/passwd` + `nss-systemd` |
| 65535 | 16bit `(uid_t) -1` | Linux | |
| 65536…524287 | Unused | | |
| 524288…1879048191 | Container UID ranges | `systemd` | `nss-systemd` |
| 1879048192…2147483647 | Unused | | |
| 2147483648…4294967294 | HIC SVNT LEONES | | |
| 4294967295 | 32bit `(uid_t) -1` | Linux | |
Note that "Unused" in the table above doesn't mean that these ranges are
really unused. It just means that these ranges have no well-established
pre-defined purposes between Linux, generic low-level distributions and
`systemd`. There might very well be other packages that allocate from these
ranges.
Note that the range 2147483648…4294967294 (i.e. 2^31…2^32-2) should be handled
with care. Various programs (including kernel file systems — see `devpts` — or
even kernel syscalls – see `setfsuid()`) have trouble with UIDs outside of the
signed 32bit range, i.e any UIDs equal to or above 2147483648. It is thus
strongly recommended to stay away from this range in order to avoid
complications. This range should be considered reserved for future, special
purposes.
## Notes on resolvability of user and group names
User names, UIDs, group names and GIDs don't have to be resolvable using NSS
(i.e. getpwuid() and getpwnam() and friends) all the time. However, systemd
makes the following requirements:
System users generally have to be resolvable during early boot already. This
means they should not be provided by any networked service (as those usually
become available during late boot only), except if a local cache is kept that
makes them available during early boot too (i.e. before networking is
up). Specifically, system users need to be resolvable at least before
`systemd-udevd.service` and `systemd-tmpfiles.service` are started, as both
need to resolve system users — but note that there might be more services
requiring full resolvability of system users than just these two.
Regular users do not need to be resolvable during early boot, it is sufficient
if they become resolvable during late boot. Specifically, regular users need to
be resolvable at the point in time the `nss-user-lookup.target` unit is
reached. This target unit is generally used as synchronization point between
providers of the user database and consumers of it. Services that require that
the user database is fully available (for example, the login service
`systemd-logind.service`) are ordered *after* it, while services that provide
parts of the user database (for example an LDAP user database client) are
ordered *before* it. Note that `nss-user-lookup.target` is a *passive* unit: in
order to minimize synchronization points on systems that don't need it the unit
is pulled into the initial transaction only if there's at least one service
that really needs it, and that means only if there's a service providing the
local user database somehow through IPC or suchlike. Or in other words: if you
hack on some networked user database project, then make sure you order your
service `Before=nss-user-lookup.target` and that you pull it in with
`Wants=nss-user-lookup.target`. However, if you hack on some project that needs
the user database to be up in full, then order your service
`After=nss-user-lookup.target`, but do *not* pull it in via a `Wants=`
dependency.
cromerc-opensysusers-a12528f/man/USER_NAMES.md 0000664 0000000 0000000 00000020505 14314710576 0021066 0 ustar 00root root 0000000 0000000 ---
title: User/Group Name Syntax
category: Users, Groups and Home Directories
layout: default
SPDX-License-Identifier: LGPL-2.1-or-later
---
# User/Group Name Syntax
The precise set of allowed user and group names on Linux systems is weakly
defined. Depending on the distribution a different set of requirements and
restrictions on the syntax of user/group names are enforced — on some
distributions the accepted syntax is even configurable by the administrator. In
the interest of interoperability systemd enforces different rules when
processing users/group defined by other subsystems and when defining users/groups
itself, following the principle of "Be conservative in what you send, be
liberal in what you accept". Also in the interest of interoperability systemd
will enforce the same rules everywhere and not make them configurable or
distribution dependent. The precise rules are described below.
Generally, the same rules apply for user as for group names.
## Other Systems
* On POSIX the set of [valid user
names](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_437)
is defined as [lower and upper case ASCII letters, digits, period,
underscore, and
hyphen](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_282),
with the restriction that hyphen is not allowed as first character of the
user name. Interestingly no size limit is declared, i.e. in neither
direction, meaning that strictly speaking according to POSIX both the empty
string is a valid user name as well as a string of gigabytes in length.
* Debian/Ubuntu based systems enforce the regular expression
`^[a-z][-a-z0-9]*$`, i.e. only lower case ASCII letters, digits and
hyphens. As first character only lowercase ASCII letters are allowed. This
regular expression is configurable by the administrator at runtime
though. This rule enforces a minimum length of one character but no maximum
length.
* Upstream shadow-utils enforces the regular expression
`^[a-z_][a-z0-9_-]*[$]$`, i.e. is similar to the Debian/Ubuntu rule, but
allows underscores and hyphens, but the latter not as first character. Also,
an optional trailing dollar character is permitted.
* Fedora/Red Hat based systems enforce the regular expression of
`^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,30}[a-zA-Z0-9_.$-]?$`, i.e. a size limit of
32 characters, with upper and lower case letters, digits, underscores,
hyphens and periods. No hyphen as first character though, and the last
character may be a dollar character. On top of that, `.` and `..` are not
allowed as user/group names.
* sssd is known to generate user names with embedded `@` and white-space
characters, as well as non-ASCII (i.e. UTF-8) user/group names.
* winbindd is known to generate user/group names with embedded `\` and
white-space characters, as well as non-ASCII (i.e. UTF-8) user/group names.
Other operating systems enforce different rules; in this documentation we'll
focus on Linux systems only however, hence those are out of scope. That said,
software like Samba is frequently deployed on Linux for providing compatibility
with Windows systems; on such systems it might be wise to stick to user/group
names also valid according to Windows rules.
## Rules systemd enforces
Distilled from the above, below are the rules systemd enforces on user/group
names. An additional, common rule between both modes listed below is that empty
strings are not valid user/group names.
Philosophically, the strict mode described below enforces an allow list of
what's allowed and prohibits everything else, while the relaxed mode described
below implements a deny list of what's not allowed and permits everything else.
### Strict mode
Strict user/group name syntax is enforced whenever a systemd component is used
to register a user or group in the system, for example a system user/group
using
[`systemd-sysusers.service`](https://www.freedesktop.org/software/systemd/man/systemd-sysusers.html)
or a regular user with
[`systemd-homed.service`](https://www.freedesktop.org/software/systemd/man/systemd-homed.html).
In strict mode, only uppercase and lowercase characters are allowed, as well as
digits, underscores and hyphens. The first character may not be a digit or
hyphen. A size limit is enforced: the minimum of `sysconf(_SC_LOGIN_NAME_MAX)`
(typically 256 on Linux; rationale: this is how POSIX suggests to detect the
limit), `UT_NAMESIZE-1` (typically 31 on Linux; rationale: names longer than
this cannot correctly appear in `utmp`/`wtmp` and create ambiguity with login
accounting) and `NAME_MAX` (255 on Linux; rationale: user names typically
appear in directory names, i.e. the home directory), thus MIN(256, 31, 255) =
31.
Note that these rules are both more strict and more relaxed than all of the
rules enforced by other systems listed above. A user/group name conforming to
systemd's strict rules will not necessarily pass a test by the rules enforced
by these other subsystems.
Written as regular expression the above is: `^[a-zA-Z_][a-zA-Z0-9_-]{0,30}$`
### Relaxed mode
Relaxed user/group name syntax is enforced whenever a systemd component accepts
and makes use of user/group names registered by other (non-systemd)
components of the system, for example in
[`systemd-logind.service`](https://www.freedesktop.org/software/systemd/man/systemd-logind.html).
Relaxed syntax is also enforced by the `User=` setting in service unit files,
i.e. for system services used for running services. Since these users may be
registered by a variety of tools relaxed mode is used, but since the primary
purpose of these users is to run a system service and thus a job for systemd a
warning is shown if the specified user name does not qualify by the strict
rules above.
* No embedded NUL bytes (rationale: handling in C must be possible and
straightforward)
* No names consisting fully of digits (rationale: avoid confusion with numeric
UID/GID specifications)
* Similar, no names consisting of an initial hyphen and otherwise entirely made
up of digits (rationale: avoid confusion with negative, numeric UID/GID
specifications, e.g. `-1`)
* No strings that do not qualify as valid UTF-8 (rationale: we want to be able
to embed these strings in JSON, with permits only valid UTF-8 in its strings;
user names using other character sets, such as JIS/Shift-JIS will cause
validation errors)
* No control characters (i.e. characters in ASCII range 1…31; rationale: they
tend to have special meaning when output on a terminal in other contexts,
moreover the newline character — as a specific control character — is used as
record separator in `/etc/passwd`, and hence it's crucial to avoid
ambiguities here)
* No colon characters (rationale: it is used as field separator in `/etc/passwd`)
* The two strings `.` and `..` are not permitted, as these have special meaning
in file system paths, and user names are frequently included in file system
paths, in particular for the purpose of home directories.
* Similar, no slashes, as these have special meaning in file system paths
* No leading or trailing white-space is permitted; and hence no user/group names
consisting of white-space only either (rationale: this typically indicates
parsing errors, and creates confusion since not visible on screen)
Note that these relaxed rules are implied by the strict rules above, i.e. all
user/group names accepted by the strict rules are also accepted by the relaxed
rules, but not vice versa.
Note that this relaxed mode does not refuse a couple of very questionable
syntaxes. For example it permits a leading or embedded period. A leading period
is problematic because the matching home directory would typically be hidden
from the user's/administrator's view. An embedded period is problematic since
it creates ambiguity in traditional `chown` syntax (which is still accepted
today) that uses it to separate user and group names in the command's
parameter: without consulting the user/group databases it is not possible to
determine if a `chown` invocation would change just the owning user or both the
owning user and group. It also allows embedding `@` (which is confusing to
MTAs).
## Common Core
Combining all rules listed above, user/group names that shall be considered
valid in all systemd contexts and on all Linux systems should match the
following regular expression (at least according to our understanding):
`^[a-z][a-z0-9-]{0,30}$`
cromerc-opensysusers-a12528f/man/custom-html.xsl 0000664 0000000 0000000 00000027503 14314710576 0022054 0 ustar 00root root 0000000 0000000