<refsect1>
<title>Description</title>
- <para><command>systemd-sysusers</command> uses the files from <filename>sysusers.d</filename> directory to create
- system users and groups at package installation or boot time. This tool may be used to allocate system users and
- groups only, it is not useful for creating non-system (i.e. regular, "human") users and groups, as it accesses
- <filename>/etc/passwd</filename> and <filename>/etc/group</filename> directly, bypassing any more complex user
- databases, for example any database involving NIS or LDAP.</para>
+ <para><command>systemd-sysusers</command> uses the files from
+ <filename>sysusers.d</filename> directory to create system users and groups and
+ to add users to groups, at package installation or boot time. This tool may be
+ used to allocate system users and groups only, it is not useful for creating
+ non-system (i.e. regular, "human") users and groups, as it accesses
+ <filename>/etc/passwd</filename> and <filename>/etc/group</filename> directly,
+ bypassing any more complex user databases, for example any database involving NIS
+ or LDAP.</para>
</refsect1>
<refsect1>
<refsect1>
<title>Configuration File Format</title>
- <para>The file format is one line per user or group containing
- name, ID, GECOS field description and home directory:</para>
+ <para>The file format is one line per user or group containing name, ID, GECOS
+ field description, home directory, and login shell:</para>
- <programlisting>#Type Name ID GECOS Home directory
-u httpd 440 "HTTP User"
-u authd /usr/bin/authd "Authorization user"
-g input - -
-m authd input
-u root 0 "Superuser" /root</programlisting>
+ <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
+g input - -
+m authd input
+u root 0 "Superuser" /root /bin/zsh</programlisting>
<para>Empty lines and lines beginning with the <literal>#</literal> character are ignored, and may be used for
commenting.</para>
<variablelist>
<varlistentry>
<term><varname>u</varname></term>
- <listitem><para>Create a system user and group of the
- specified name should they not exist yet. The user's primary
- group will be set to the group bearing the same name. The
- user's shell will be set to
- <filename>/sbin/nologin</filename>, the home directory to
- the specified home directory, or <filename>/</filename> if
- none is given. The account will be created disabled, so that
- logins are not allowed.</para></listitem>
+ <listitem><para>Create a system user and group of the specified name should
+ they not exist yet. The user's primary group will be set to the group
+ bearing the same name. The account will be created disabled, so that logins
+ are not allowed.</para></listitem>
</varlistentry>
<varlistentry>
numeric 32-bit UID or GID of the user/group. Do not use IDs 65535
or 4294967295, as they have special placeholder meanings.
Specify <literal>-</literal> for automatic UID/GID allocation
- for the user or group. Alternatively, specify an absolute path
+ for the user or group (this is strongly recommended unless it is strictly
+ necessary to use a specific UID or GID). Alternatively, specify an absolute path
in the file system. In this case, the UID/GID is read from the
path's owner/group. This is useful to create users whose UID/GID
match the owners of pre-existing files (such as SUID or SGID
<refsect2>
<title>GECOS</title>
- <para>A short, descriptive string for users to be created,
- enclosed in quotation marks. Note that this field may not
- contain colons.</para>
+ <para>A short, descriptive string for users to be created, enclosed in
+ quotation marks. Note that this field may not contain colons.</para>
- <para>Only applies to lines of type <varname>u</varname> and
- should otherwise be left unset, or be set to
- <literal>-</literal>.</para>
+ <para>Only applies to lines of type <varname>u</varname> and should otherwise
+ be left unset (or <literal>-</literal>).</para>
</refsect2>
<refsect2>
<title>Home Directory</title>
- <para>The home directory for a new system user. If omitted,
- defaults to the root directory. It is recommended to not
- unnecessarily specify home directories for system users, unless
- software strictly requires one to be set.</para>
+ <para>The home directory for a new system user. If omitted, defaults to the
+ root directory.</para>
- <para>Only applies to lines of type <varname>u</varname> and
- should otherwise be left unset, or be set to
- <literal>-</literal>.</para>
+ <para>Only applies to lines of type <varname>u</varname> and should otherwise
+ be left unset (or <literal>-</literal>). It is recommended to omit this, unless
+ software strictly requires a home directory to be set.</para>
+ </refsect2>
+
+ <refsect2>
+ <title>Shell</title>
+
+ <para>The login shell of the user. If not specified, this will be set to
+ <filename>/sbin/nologin</filename>, except if the UID of the user is 0, in
+ which case <filename>/bin/sh</filename> will be used.</para>
+
+ <para>Only applies to lines of type <varname>u</varname> and should otherwise
+ be left unset (or <literal>-</literal>). It is recommended to omit this, unless
+ a shell different <filename>/sbin/nologin</filename> must be used.</para>
</refsect2>
</refsect1>
<refsect1>
<title>Idempotence</title>
- <para>Note that <command>systemd-sysusers</command> will do
- nothing if the specified users or groups already exist, so
- normally, there is no reason to override
- <filename>sysusers.d</filename> vendor configuration, except to
- block certain users or groups from being created.</para>
+ <para>Note that <command>systemd-sysusers</command> will do nothing if the
+ specified users or groups already exist or the users are members of specified
+ groups, so normally there is no reason to override
+ <filename>sysusers.d</filename> vendor configuration, except to block certain
+ users or groups from being created.</para>
</refsect1>
<refsect1>
char *gid_path;
char *description;
char *home;
+ char *shell;
gid_t gid;
uid_t uid;
return r;
}
+static const char* default_shell(uid_t uid) {
+ return uid == 0 ? "/bin/sh" : "/sbin/nologin";
+}
+
static int write_temporary_passwd(const char *passwd_path, FILE **tmpfile, char **tmpfile_path) {
_cleanup_fclose_ FILE *original = NULL, *passwd = NULL;
_cleanup_(unlink_and_freep) char *passwd_tmp = NULL;
/* Initialize the shell to nologin, with one exception:
* for root we patch in something special */
- .pw_shell = i->uid == 0 ? (char*) "/bin/sh" : (char*) "/sbin/nologin",
+ .pw_shell = i->shell ?: (char*) default_shell(i->uid),
};
errno = 0;
free(i->gid_path);
free(i->description);
free(i->home);
+ free(i->shell);
free(i);
}
if (!streq_ptr(a->home, b->home))
return false;
+ if (!streq_ptr(a->shell, b->shell))
+ return false;
+
return true;
}
{}
};
- _cleanup_free_ char *action = NULL, *name = NULL, *id = NULL, *resolved_name = NULL, *resolved_id = NULL, *description = NULL, *home = NULL;
+ _cleanup_free_ char *action = NULL,
+ *name = NULL, *resolved_name = NULL,
+ *id = NULL, *resolved_id = NULL,
+ *description = NULL,
+ *home = NULL,
+ *shell, *resolved_shell = NULL;
_cleanup_(item_freep) Item *i = NULL;
Item *existing;
OrderedHashmap *h;
/* Parse columns */
p = buffer;
- r = extract_many_words(&p, NULL, EXTRACT_QUOTES, &action, &name, &id, &description, &home, NULL);
+ r = extract_many_words(&p, NULL, EXTRACT_QUOTES,
+ &action, &name, &id, &description, &home, &shell, NULL);
if (r < 0) {
log_error("[%s:%u] Syntax error.", fname, line);
return r;
}
}
+ /* Verify shell */
+ if (isempty(shell) || streq(shell, "-"))
+ shell = mfree(shell);
+
+ if (shell) {
+ r = specifier_printf(shell, specifier_table, NULL, &resolved_shell);
+ if (r < 0) {
+ log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, shell);
+ return r;
+ }
+
+ if (!valid_shell(resolved_shell)) {
+ log_error("[%s:%u] '%s' is not a valid login shell field.", fname, line, resolved_shell);
+ return -EINVAL;
+ }
+ }
+
+
switch (action[0]) {
case ADD_RANGE:
return -EINVAL;
}
- if (description) {
- log_error("[%s:%u] Lines of type 'r' don't take a GECOS field.", fname, line);
- return -EINVAL;
- }
-
- if (home) {
- log_error("[%s:%u] Lines of type 'r' don't take a home directory field.", fname, line);
+ if (description || home || shell) {
+ log_error("[%s:%u] Lines of type '%c' don't take a %s field.",
+ fname, line, action[0],
+ description ? "GECOS" : home ? "home directory" : "login shell");
return -EINVAL;
}
return -EINVAL;
}
- if (description) {
- log_error("[%s:%u] Lines of type 'm' don't take a GECOS field.", fname, line);
- return -EINVAL;
- }
-
- if (home) {
- log_error("[%s:%u] Lines of type 'm' don't take a home directory field.", fname, line);
+ if (description || home || shell) {
+ log_error("[%s:%u] Lines of type '%c' don't take a %s field.",
+ fname, line, action[0],
+ description ? "GECOS" : home ? "home directory" : "login shell");
return -EINVAL;
}
i->home = home;
home = NULL;
+ i->shell = resolved_shell;
+ resolved_shell = NULL;
+
h = users;
break;
return -EINVAL;
}
- if (description) {
- log_error("[%s:%u] Lines of type 'g' don't take a GECOS field.", fname, line);
- return -EINVAL;
- }
-
- if (home) {
- log_error("[%s:%u] Lines of type 'g' don't take a home directory field.", fname, line);
+ if (description || home || shell) {
+ log_error("[%s:%u] Lines of type '%c' don't take a %s field.",
+ fname, line, action[0],
+ description ? "GECOS" : home ? "home directory" : "login shell");
return -EINVAL;
}