]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sysusers: add new ! line flag for creating fully locked accounts
authorLennart Poettering <lennart@poettering.net>
Wed, 23 Oct 2024 20:22:15 +0000 (22:22 +0200)
committerLennart Poettering <lennart@poettering.net>
Tue, 29 Oct 2024 10:00:13 +0000 (11:00 +0100)
Fixes: #13522
man/sysusers.d.xml
src/sysusers/sysusers.c

index f5f12381d6eef2007c99007f61e130c4f9f14a3e..4b54286e7fbac2da1d52b7b068ba8bdf4db1f238 100644 (file)
@@ -93,9 +93,9 @@ r     -          lowest-highest</programlisting>
     field description, home directory, and login shell:</para>
 
     <programlisting>#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.</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>
         </varlistentry>
 
index 8ec1373479814b407fc3b2fbb3b579d9acc005a8..44253483dba028c894692a73ba76264a77bb0184 100644 (file)
@@ -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.",