From 2ec7977e1b100c1717d95417e6d825fbf939f7b3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 23 Oct 2024 22:22:15 +0200 Subject: [PATCH] sysusers: add new ! line flag for creating fully locked accounts Fixes: #13522 --- man/sysusers.d.xml | 12 +++++++++--- src/sysusers/sysusers.c | 32 +++++++++++++++++++++++++++----- 2 files changed, 36 insertions(+), 8 deletions(-) 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/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.", -- 2.47.3