1
0
mirror of https://github.com/systemd/systemd.git synced 2025-01-03 05:18:09 +03:00

sysusers: add new ! line flag for creating fully locked accounts

Fixes: #13522
This commit is contained in:
Lennart Poettering 2024-10-23 22:22:15 +02:00
parent 815569791f
commit 2ec7977e1b
2 changed files with 36 additions and 8 deletions

View File

@ -93,9 +93,9 @@ r - lowest-highest</programlisting>
field description, home directory, and login shell:</para> field description, home directory, and login shell:</para>
<programlisting>#Type Name ID GECOS Home directory Shell <programlisting>#Type Name ID GECOS Home directory Shell
u httpd 404 "HTTP User" u! httpd 404 "HTTP User"
u _authd /usr/bin/authd "Authorization user" u! _authd /usr/bin/authd "Authorization user"
u postgres - "Postgresql Database" /var/lib/pgsql /usr/libexec/postgresdb u! postgres - "Postgresql Database" /var/lib/pgsql /usr/libexec/postgresdb
g input - - g input - -
m _authd input m _authd input
u root 0 "Superuser" /root /bin/zsh 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 bearing the same name unless the ID field specifies it. The account will be
created disabled, so that logins are not allowed.</para> created disabled, so that logins are not allowed.</para>
<para>Type <varname>u</varname> may be suffixed with an exclamation mark (<literal>u!</literal>) 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
<literal>u!</literal>, the account is also locked, which makes a difference for non-password forms
of authentication, such as SSH or similar.</para>
<xi:include href="version-info.xml" xpointer="v215"/></listitem> <xi:include href="version-info.xml" xpointer="v215"/></listitem>
</varlistentry> </varlistentry>

View File

@ -86,6 +86,8 @@ typedef struct Item {
bool uid_set; bool uid_set;
bool locked;
bool todo_user; bool todo_user;
bool todo_group; bool todo_group;
} Item; } Item;
@ -654,7 +656,7 @@ static int write_temporary_shadow(
.sp_max = -1, .sp_max = -1,
.sp_warn = -1, .sp_warn = -1,
.sp_inact = -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 ... */ .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), return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EINVAL),
"Trailing garbage."); "Trailing garbage.");
/* Verify action */ if (isempty(action))
if (strlen(action) != 1) return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG),
return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EINVAL), "Empty command specification.");
"Unknown modifier '%s'.", action);
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)) if (!IN_SET(action[0], ADD_USER, ADD_GROUP, ADD_MEMBER, ADD_RANGE))
return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG), return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG),
@ -1793,6 +1802,10 @@ static int parse_line(
switch (action[0]) { switch (action[0]) {
case ADD_RANGE: 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) if (resolved_name)
return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EINVAL), return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EINVAL),
"Lines of type 'r' don't take a name field."); "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), return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EINVAL),
"Lines of type 'm' require a user name in the second field."); "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) if (!resolved_id)
return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EINVAL), return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EINVAL),
"Lines of type 'm' require a group name in the third field."); "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->description = TAKE_PTR(resolved_description);
i->home = TAKE_PTR(resolved_home); i->home = TAKE_PTR(resolved_home);
i->shell = TAKE_PTR(resolved_shell); i->shell = TAKE_PTR(resolved_shell);
i->locked = locked;
h = c->users; h = c->users;
break; break;
@ -1895,6 +1913,10 @@ static int parse_line(
return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EINVAL), return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EINVAL),
"Lines of type 'g' require a user name in the second field."); "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) if (description || home || shell)
return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EINVAL), return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EINVAL),
"Lines of type '%c' don't take a %s field.", "Lines of type '%c' don't take a %s field.",