diff --git a/man/sysusers.d.xml b/man/sysusers.d.xml index f5f12381d6e..4b54286e7fb 100644 --- a/man/sysusers.d.xml +++ b/man/sysusers.d.xml @@ -93,9 +93,9 @@ r - lowest-highest field description, home directory, and login shell: #Type Name ID GECOS Home directory Shell -u httpd 404 "HTTP User" -u _authd /usr/bin/authd "Authorization user" -u postgres - "Postgresql Database" /var/lib/pgsql /usr/libexec/postgresdb +u! httpd 404 "HTTP User" +u! _authd /usr/bin/authd "Authorization user" +u! postgres - "Postgresql Database" /var/lib/pgsql /usr/libexec/postgresdb g input - - m _authd input u root 0 "Superuser" /root /bin/zsh @@ -119,6 +119,12 @@ r - 500-900 bearing the same name unless the ID field specifies it. The account will be created disabled, so that logins are not allowed. + Type u may be suffixed with an exclamation mark (u!) to + create a fully locked account. This is recommended, since logins should typically not be allowed + for system users. With or without the exclamation mark an invalid password is set. For + u!, the account is also locked, which makes a difference for non-password forms + of authentication, such as SSH or similar. + diff --git a/mkosi.images/build/mkosi.conf.d/centos-fedora/mkosi.conf b/mkosi.images/build/mkosi.conf.d/centos-fedora/mkosi.conf index 0f4a79652cb..473dc362b52 100644 --- a/mkosi.images/build/mkosi.conf.d/centos-fedora/mkosi.conf +++ b/mkosi.images/build/mkosi.conf.d/centos-fedora/mkosi.conf @@ -8,7 +8,7 @@ Distribution=|fedora Environment= GIT_URL=https://src.fedoraproject.org/rpms/systemd.git GIT_BRANCH=rawhide - GIT_COMMIT=a67221c3f0d0b81b9b5b3230a71d09044342f1a4 + GIT_COMMIT=e42eed4afd6267cd954d393d8eec79e0e7573de0 PKG_SUBDIR=fedora [Content] diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c index 8ec13734798..44253483dba 100644 --- a/src/sysusers/sysusers.c +++ b/src/sysusers/sysusers.c @@ -86,6 +86,8 @@ typedef struct Item { bool uid_set; + bool locked; + bool todo_user; bool todo_group; } Item; @@ -654,7 +656,7 @@ static int write_temporary_shadow( .sp_max = -1, .sp_warn = -1, .sp_inact = -1, - .sp_expire = -1, + .sp_expire = i->locked ? 1 : -1, /* Negative expiration means "unset". Expiration 0 or 1 means "locked" */ .sp_flag = ULONG_MAX, /* this appears to be what everybody does ... */ }; @@ -1707,10 +1709,17 @@ static int parse_line( return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EINVAL), "Trailing garbage."); - /* Verify action */ - if (strlen(action) != 1) - return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EINVAL), - "Unknown modifier '%s'.", action); + if (isempty(action)) + return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG), + "Empty command specification."); + + bool locked = false; + for (int pos = 1; action[pos]; pos++) + if (action[pos] == '!' && !locked) + locked = true; + else + return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG), + "Unknown modifiers in command '%s'.", action); if (!IN_SET(action[0], ADD_USER, ADD_GROUP, ADD_MEMBER, ADD_RANGE)) return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG), @@ -1793,6 +1802,10 @@ static int parse_line( switch (action[0]) { case ADD_RANGE: + if (locked) + return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EINVAL), + "Flag '!' not permitted on lines of type 'r'."); + if (resolved_name) return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EINVAL), "Lines of type 'r' don't take a name field."); @@ -1820,6 +1833,10 @@ static int parse_line( return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EINVAL), "Lines of type 'm' require a user name in the second field."); + if (locked) + return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EINVAL), + "Flag '!' not permitted on lines of type 'm'."); + if (!resolved_id) return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EINVAL), "Lines of type 'm' require a group name in the third field."); @@ -1886,6 +1903,7 @@ static int parse_line( i->description = TAKE_PTR(resolved_description); i->home = TAKE_PTR(resolved_home); i->shell = TAKE_PTR(resolved_shell); + i->locked = locked; h = c->users; break; @@ -1895,6 +1913,10 @@ static int parse_line( return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EINVAL), "Lines of type 'g' require a user name in the second field."); + if (locked) + return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EINVAL), + "Flag '!' not permitted on lines of type 'g'."); + if (description || home || shell) return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EINVAL), "Lines of type '%c' don't take a %s field.", diff --git a/sysusers.d/basic.conf.in b/sysusers.d/basic.conf.in index 0aec080a4cb..992af346ca6 100644 --- a/sysusers.d/basic.conf.in +++ b/sysusers.d/basic.conf.in @@ -11,7 +11,7 @@ u root 0:0 "Super User" /root # The nobody user/group for NFS file systems g {{NOBODY_GROUP_NAME}} 65534 - - -u {{NOBODY_USER_NAME }} 65534:65534 "Kernel Overflow User" - +u! {{NOBODY_USER_NAME }} 65534:65534 "Kernel Overflow User" - # Administrator group: can *see* more than normal users g adm {{ADM_GID }} - - diff --git a/sysusers.d/systemd-coredump.conf b/sysusers.d/systemd-coredump.conf index c4ff003bd60..2ab8a41b9da 100644 --- a/sysusers.d/systemd-coredump.conf +++ b/sysusers.d/systemd-coredump.conf @@ -5,4 +5,4 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -u systemd-coredump - "systemd Core Dumper" +u! systemd-coredump - "systemd Core Dumper" diff --git a/sysusers.d/systemd-network.conf.in b/sysusers.d/systemd-network.conf.in index 7c64a4681fd..fc04827efdd 100644 --- a/sysusers.d/systemd-network.conf.in +++ b/sysusers.d/systemd-network.conf.in @@ -5,4 +5,4 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -u systemd-network {{SYSTEMD_NETWORK_UID}} "systemd Network Management" +u! systemd-network {{SYSTEMD_NETWORK_UID}} "systemd Network Management" diff --git a/sysusers.d/systemd-oom.conf b/sysusers.d/systemd-oom.conf index 27e571feb5e..1ce3d23b6be 100644 --- a/sysusers.d/systemd-oom.conf +++ b/sysusers.d/systemd-oom.conf @@ -5,4 +5,4 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -u systemd-oom - "systemd Userspace OOM Killer" +u! systemd-oom - "systemd Userspace OOM Killer" diff --git a/sysusers.d/systemd-remote.conf b/sysusers.d/systemd-remote.conf index ca20c248961..796850c9e61 100644 --- a/sysusers.d/systemd-remote.conf +++ b/sysusers.d/systemd-remote.conf @@ -5,4 +5,4 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -u systemd-journal-remote - "systemd Journal Remote" +u! systemd-journal-remote - "systemd Journal Remote" diff --git a/sysusers.d/systemd-resolve.conf.in b/sysusers.d/systemd-resolve.conf.in index 9f02ef94e6e..e385070c45b 100644 --- a/sysusers.d/systemd-resolve.conf.in +++ b/sysusers.d/systemd-resolve.conf.in @@ -5,4 +5,4 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -u systemd-resolve {{SYSTEMD_RESOLVE_UID}} "systemd Resolver" +u! systemd-resolve {{SYSTEMD_RESOLVE_UID}} "systemd Resolver" diff --git a/sysusers.d/systemd-timesync.conf.in b/sysusers.d/systemd-timesync.conf.in index e50f0254169..7b9fb3d8d9f 100644 --- a/sysusers.d/systemd-timesync.conf.in +++ b/sysusers.d/systemd-timesync.conf.in @@ -5,4 +5,4 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -u systemd-timesync {{SYSTEMD_TIMESYNC_UID}} "systemd Time Synchronization" +u! systemd-timesync {{SYSTEMD_TIMESYNC_UID}} "systemd Time Synchronization" diff --git a/test/units/TEST-74-AUX-UTILS.sysusers.sh b/test/units/TEST-74-AUX-UTILS.sysusers.sh index dcd29938b53..2a06e85bfd4 100755 --- a/test/units/TEST-74-AUX-UTILS.sysusers.sh +++ b/test/units/TEST-74-AUX-UTILS.sysusers.sh @@ -6,6 +6,17 @@ set -o pipefail # shellcheck source=test/units/util.sh . "$(dirname "$0")"/util.sh +systemd-sysusers - <