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
+2. 60578…60705 → UIDs for dynamic greeter users are allocated from this range.
+ In multiseat scenarios, multiple greeter sessions may be running at once.
+ However, systemd only permits one graphical session at a time per user
+ ([documentation](/DESKTOP_ENVIRONMENTS)). Thus, multiseat-enabled display
+ managers (like GDM) must run each greeter session under a unique user. To
+ make use of this UID range, the display manager should implement the
+ [userdb Varlink API](/USER_GROUP_API) and dynamically allocate users whenever
+ they are needed by the display manager. Display managers may also use these
+ UIDs for other purposes where dynamic users may be helpful (i.e. guest user
+ sessions or kiosk sessions)
+
+3. 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 16-bit boundary
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
+4. 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 16-bit subrange of this
range and assign it to the container.
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.
-4. 2147352576…2147418111 → UID range used for foreign OS images. For various
+5. 2147352576…2147418111 → UID range used for foreign OS images. For various
usecases (primarily: containers) it makes sense to make foreign OS images
available locally whose UID/GID ownerships do not make sense in the local
context but only within the OS image itself. This 64K UID range can be used
```sh
$ pkg-config --variable=system_uid_max systemd
999
+$ pkg-config --variable=greeter_uid_min systemd
+60578
+$ pkg-config --variable=greeter_uid_max systemd
+60705
$ pkg-config --variable=dynamic_uid_min systemd
61184
$ pkg-config --variable=dynamic_uid_max systemd
| 1000…60000 | 0x000003E8…0x00001770 | 59000 | Regular users | Distributions | `/etc/passwd` + LDAP/NIS/… |
| 60001…60513 | 0x0000EA61…0x0000EC61 | 513 | Human users (homed) | `systemd` | `nss-systemd` |
| 60514…60577 | 0x0000EC62…0x0000ECA1 | 64 | Host users mapped into containers | `systemd` | `systemd-nspawn` |
-| 60578…61183 | 0x0000ECA2…0x0000EEFF | 606 | *unused* | | |
+| 60578…60705 | 0x0000ECA2…0x0000ED21 | 128 | Dynamic greeter users | `systemd` | `nss-systemd` |
+| 60706…61183 | 0x0000ED22…0x0000EEFF | 478 | *unused* | | |
| 61184…65519 | 0x0000EF00…0x0000FFEF | 4336 | Dynamic service users | `systemd` | `nss-systemd` |
| 65520…65533 | 0x0000FFF0…0x0000FFFD | 13 | *unused* | | |
| 65534 | 0x0000FFFE | 1 | `nobody` user | Linux | `/etc/passwd` + `nss-systemd` |
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 theseranges.
+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
error('Invalid gid allocation range')
endif
+greeter_uid_min = get_option('greeter-uid-min')
+greeter_uid_max = get_option('greeter-uid-max')
+conf.set('GREETER_UID_MIN', greeter_uid_min)
+conf.set('GREETER_UID_MAX', greeter_uid_max)
+
dynamic_uid_min = get_option('dynamic-uid-min')
dynamic_uid_max = get_option('dynamic-uid-max')
conf.set('DYNAMIC_UID_MIN', dynamic_uid_min)
conf.get('SYSTEM_ALLOC_UID_MIN')),
'system GIDs' : '<=@0@ (alloc >=@1@)'.format(conf.get('SYSTEM_GID_MAX'),
conf.get('SYSTEM_ALLOC_GID_MIN')),
+ 'greeter UIDs' : '@0@…@1@'.format(greeter_uid_min, greeter_uid_max),
'dynamic UIDs' : '@0@…@1@'.format(dynamic_uid_min, dynamic_uid_max),
'container UID bases' : '@0@…@1@'.format(container_uid_base_min, container_uid_base_max),
'foreign UID base' : '@0@'.format(foreign_uid_base),
description : 'maximum system UID')
option('system-gid-max', type : 'integer', value : 0,
description : 'maximum system GID')
+option('greeter-uid-min', type : 'integer', value : 0x0000ECA2,
+ description : 'minimum greeter UID')
+option('greeter-uid-max', type : 'integer', value : 0x0000ED21,
+ description : 'maximum greeter UID')
option('dynamic-uid-min', type : 'integer', value : 0x0000EF00,
description : 'minimum dynamic UID')
option('dynamic-uid-max', type : 'integer', value : 0x0000FFEF,
/* Returns true if the specified UID shall get its data stored in the system journal. */
- return uid_is_system(uid) || uid_is_dynamic(uid) || uid == UID_NOBODY || uid_is_container(uid) || uid_is_foreign(uid);
+ return uid_is_system(uid) || uid_is_dynamic(uid) || uid_is_greeter(uid) || uid == UID_NOBODY || uid_is_container(uid) || uid_is_foreign(uid);
}
bool uid_is_system(uid_t uid);
bool gid_is_system(gid_t gid);
+static inline bool uid_is_greeter(uid_t uid) {
+ return GREETER_UID_MIN <= uid && uid <= GREETER_UID_MAX;
+}
+
static inline bool uid_is_dynamic(uid_t uid) {
return DYNAMIC_UID_MIN <= uid && uid <= DYNAMIC_UID_MAX;
}
system_gid_max={{SYSTEM_GID_MAX}}
systemgidmax=${system_gid_max}
+greeter_uid_min={{GREETER_UID_MIN}}
+greeter_uid_max={{GREETER_UID_MAX}}
+
dynamic_uid_min={{DYNAMIC_UID_MIN}}
dynamicuidmin=${dynamic_uid_min}
dynamic_uid_max={{DYNAMIC_UID_MAX}}
if (!allow_user)
return 0;
- if (uid_is_system(uid) || uid_is_dynamic(uid) || uid == UID_NOBODY)
+ if (uid_is_system(uid) || uid_is_dynamic(uid) || uid_is_greeter(uid) || uid == UID_NOBODY)
return 0;
/* Make sure normal users can read (but not write or delete) their own coredumps */
return ansi_highlight_yellow4(); /* files should never be owned by 'nobody' (but might happen due to userns mapping) */
if (uid_is_system(uid))
return ansi_normal(); /* files in disk images are typically owned by root and other system users, no issue there */
- if (uid_is_dynamic(uid))
+ if (uid_is_dynamic(uid) || uid_is_greeter(uid))
return ansi_highlight_red(); /* files should never be owned persistently by dynamic users, and there are just no excuses */
if (uid_is_container(uid) || uid_is_foreign(uid))
return ansi_highlight_cyan();
if (uid_is_system(uid))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "UID " UID_FMT " is in system range, refusing.", uid);
+ if (uid_is_greeter(uid))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "UID " UID_FMT " is in greeter range, refusing.", uid);
if (uid_is_dynamic(uid))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "UID " UID_FMT " is in dynamic range, refusing.", uid);
if (uid == UID_NOBODY)
/* Insist we are outside of the dynamic and system range */
if (uid_is_system(hr->uid) || gid_is_system(user_record_gid(hr)) ||
- uid_is_dynamic(hr->uid) || gid_is_dynamic(user_record_gid(hr)))
+ uid_is_dynamic(hr->uid) || gid_is_dynamic(user_record_gid(hr)) ||
+ uid_is_greeter(hr->uid))
return -EADDRNOTAVAIL;
/* Insist that GID and UID match */
if (uid_is_system(h->uid))
return USER_SYSTEM;
- if (uid_is_dynamic(h->uid))
+ if (uid_is_dynamic(h->uid) || uid_is_greeter(h->uid))
return USER_DYNAMIC;
if (uid_is_container(h->uid))