useradd/usermod: add --selinux-range argument

Add a command line argument to useradd(8) and usermod(8) to specify the
MLS range for a SELinux user mapping.

Improves: #676
This commit is contained in:
Christian Göttsche 2023-04-01 14:34:56 +02:00 committed by Iker Pedrosa
parent 97f79e3b27
commit c80788a3ac
6 changed files with 98 additions and 10 deletions

View File

@ -385,7 +385,7 @@ extern int check_selinux_permit (const char *perm_name);
/* semanage.c */ /* semanage.c */
#ifdef WITH_SELINUX #ifdef WITH_SELINUX
extern int set_seuser(const char *login_name, const char *seuser_name); extern int set_seuser(const char *login_name, const char *seuser_name, const char *serange);
extern int del_seuser(const char *login_name); extern int del_seuser(const char *login_name);
#endif #endif

View File

@ -105,7 +105,8 @@ fail:
static int semanage_user_mod (semanage_handle_t *handle, static int semanage_user_mod (semanage_handle_t *handle,
semanage_seuser_key_t *key, semanage_seuser_key_t *key,
const char *login_name, const char *login_name,
const char *seuser_name) const char *seuser_name,
const char *serange)
{ {
int ret; int ret;
semanage_seuser_t *seuser = NULL; semanage_seuser_t *seuser = NULL;
@ -118,6 +119,17 @@ static int semanage_user_mod (semanage_handle_t *handle,
goto done; goto done;
} }
if (serange && semanage_mls_enabled(handle)) {
ret = semanage_seuser_set_mlsrange (handle, seuser, serange);
if (ret != 0) {
fprintf (shadow_logfd,
_("Could not set serange for %s to %s\n"),
login_name, serange);
ret = 1;
goto done;
}
}
ret = semanage_seuser_set_sename (handle, seuser, seuser_name); ret = semanage_seuser_set_sename (handle, seuser, seuser_name);
if (ret != 0) { if (ret != 0) {
fprintf (shadow_logfd, fprintf (shadow_logfd,
@ -146,7 +158,8 @@ done:
static int semanage_user_add (semanage_handle_t *handle, static int semanage_user_add (semanage_handle_t *handle,
semanage_seuser_key_t *key, semanage_seuser_key_t *key,
const char *login_name, const char *login_name,
const char *seuser_name) const char *seuser_name,
const char *serange)
{ {
int ret; int ret;
semanage_seuser_t *seuser = NULL; semanage_seuser_t *seuser = NULL;
@ -167,6 +180,17 @@ static int semanage_user_add (semanage_handle_t *handle,
goto done; goto done;
} }
if (serange && semanage_mls_enabled(handle)) {
ret = semanage_seuser_set_mlsrange (handle, seuser, serange);
if (ret != 0) {
fprintf (shadow_logfd,
_("Could not set serange for %s to %s\n"),
login_name, serange);
ret = 1;
goto done;
}
}
ret = semanage_seuser_set_sename (handle, seuser, seuser_name); ret = semanage_seuser_set_sename (handle, seuser, seuser_name);
if (ret != 0) { if (ret != 0) {
fprintf (shadow_logfd, fprintf (shadow_logfd,
@ -192,7 +216,7 @@ done:
} }
int set_seuser (const char *login_name, const char *seuser_name) int set_seuser (const char *login_name, const char *seuser_name, const char *serange)
{ {
semanage_handle_t *handle = NULL; semanage_handle_t *handle = NULL;
semanage_seuser_key_t *key = NULL; semanage_seuser_key_t *key = NULL;
@ -226,7 +250,7 @@ int set_seuser (const char *login_name, const char *seuser_name)
} }
if (0 != seuser_exists) { if (0 != seuser_exists) {
ret = semanage_user_mod (handle, key, login_name, seuser_name); ret = semanage_user_mod (handle, key, login_name, seuser_name, serange);
if (ret != 0) { if (ret != 0) {
fprintf (shadow_logfd, fprintf (shadow_logfd,
_("Cannot modify SELinux user mapping\n")); _("Cannot modify SELinux user mapping\n"));
@ -234,7 +258,7 @@ int set_seuser (const char *login_name, const char *seuser_name)
goto done; goto done;
} }
} else { } else {
ret = semanage_user_add (handle, key, login_name, seuser_name); ret = semanage_user_add (handle, key, login_name, seuser_name, serange);
if (ret != 0) { if (ret != 0) {
fprintf (shadow_logfd, fprintf (shadow_logfd,
_("Cannot add SELinux user mapping\n")); _("Cannot add SELinux user mapping\n"));

View File

@ -570,13 +570,31 @@
<listitem> <listitem>
<para> <para>
defines the SELinux user for the new account. Without this defines the SELinux user for the new account. Without this
option, a SELinux uses the default user. Note that the option, SELinux uses the default user. Note that the
shadow system doesn't store the selinux-user, it uses shadow system doesn't store the selinux-user, it uses
<citerefentry><refentrytitle>semanage</refentrytitle> <citerefentry><refentrytitle>semanage</refentrytitle>
<manvolnum>8</manvolnum></citerefentry> for that. <manvolnum>8</manvolnum></citerefentry> for that.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term>
<option>--selinux-range</option>&nbsp;<replaceable>SERANGE</replaceable>
</term>
<listitem>
<para>
defines the SELinux MLS range for the new account. Without this
option, SELinux uses the default range. Note that the
shadow system doesn't store the selinux-range, it uses
<citerefentry><refentrytitle>semanage</refentrytitle>
<manvolnum>8</manvolnum></citerefentry> for that.
</para>
<para>
This option is only valid if the <option>-Z</option> (or
<option>--selinux-user</option>) option is specified.
</para>
</listitem>
</varlistentry>
</variablelist> </variablelist>
<refsect2 id='changing_the_default_values'> <refsect2 id='changing_the_default_values'>

View File

@ -510,6 +510,23 @@
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term>
<option>--selinux-range</option>&nbsp;<replaceable>SERANGE</replaceable>
</term>
<listitem>
<para>
defines the SELinux MLS range for the new account.
Note that the shadow system doesn't store the selinux-range,
it uses <citerefentry><refentrytitle>semanage</refentrytitle>
<manvolnum>8</manvolnum></citerefentry> for that.
</para>
<para>
This option is only valid if the <option>-Z</option> (or
<option>--selinux-user</option>) option is specified.
</para>
</listitem>
</varlistentry>
</variablelist> </variablelist>
</refsect1> </refsect1>

View File

@ -113,6 +113,7 @@ static const char *prefix_user_home = NULL;
#ifdef WITH_SELINUX #ifdef WITH_SELINUX
static /*@notnull@*/const char *user_selinux = ""; static /*@notnull@*/const char *user_selinux = "";
static const char *user_selinux_range = NULL;
#endif /* WITH_SELINUX */ #endif /* WITH_SELINUX */
static long user_expire = -1; static long user_expire = -1;
@ -997,6 +998,7 @@ static void usage (int status)
(void) fputs (_(" -U, --user-group create a group with the same name as the user\n"), usageout); (void) fputs (_(" -U, --user-group create a group with the same name as the user\n"), usageout);
#ifdef WITH_SELINUX #ifdef WITH_SELINUX
(void) fputs (_(" -Z, --selinux-user SEUSER use a specific SEUSER for the SELinux user mapping\n"), usageout); (void) fputs (_(" -Z, --selinux-user SEUSER use a specific SEUSER for the SELinux user mapping\n"), usageout);
(void) fputs (_(" --selinux-range SERANGE use a specific MLS range for the SELinux user mapping\n"), usageout);
#endif /* WITH_SELINUX */ #endif /* WITH_SELINUX */
(void) fputs ("\n", usageout); (void) fputs ("\n", usageout);
exit (status); exit (status);
@ -1280,6 +1282,7 @@ static void process_flags (int argc, char **argv)
{"user-group", no_argument, NULL, 'U'}, {"user-group", no_argument, NULL, 'U'},
#ifdef WITH_SELINUX #ifdef WITH_SELINUX
{"selinux-user", required_argument, NULL, 'Z'}, {"selinux-user", required_argument, NULL, 'Z'},
{"selinux-range", required_argument, NULL, 202},
#endif /* WITH_SELINUX */ #endif /* WITH_SELINUX */
{NULL, 0, NULL, '\0'} {NULL, 0, NULL, '\0'}
}; };
@ -1529,6 +1532,9 @@ static void process_flags (int argc, char **argv)
exit (E_BAD_ARG); exit (E_BAD_ARG);
} }
break; break;
case 202:
user_selinux_range = optarg;
break;
#endif /* WITH_SELINUX */ #endif /* WITH_SELINUX */
default: default:
usage (E_USAGE); usage (E_USAGE);
@ -1576,6 +1582,14 @@ static void process_flags (int argc, char **argv)
Prog, "-m", "-M"); Prog, "-m", "-M");
usage (E_USAGE); usage (E_USAGE);
} }
#ifdef WITH_SELINUX
if (user_selinux_range && !Zflg) {
fprintf (stderr,
_("%s: %s flag is only allowed with the %s flag\n"),
Prog, "--selinux-range", "--selinux-user");
usage (E_USAGE);
}
#endif /* WITH_SELINUX */
/* /*
* Either -D or username is required. Defaults can be set with -D * Either -D or username is required. Defaults can be set with -D
@ -2760,7 +2774,7 @@ int main (int argc, char **argv)
#ifdef WITH_SELINUX #ifdef WITH_SELINUX
if (Zflg) { if (Zflg) {
if (set_seuser (user_name, user_selinux) != 0) { if (set_seuser (user_name, user_selinux, user_selinux_range) != 0) {
fprintf (stderr, fprintf (stderr,
_("%s: warning: the user name %s to %s SELinux user mapping failed.\n"), _("%s: warning: the user name %s to %s SELinux user mapping failed.\n"),
Prog, user_name, user_selinux); Prog, user_name, user_selinux);

View File

@ -100,6 +100,7 @@ static char *user_newhome;
static char *user_shell; static char *user_shell;
#ifdef WITH_SELINUX #ifdef WITH_SELINUX
static const char *user_selinux = ""; static const char *user_selinux = "";
static const char *user_selinux_range = NULL;
#endif /* WITH_SELINUX */ #endif /* WITH_SELINUX */
static char *user_newshell; static char *user_newshell;
static long user_expire; static long user_expire;
@ -405,6 +406,7 @@ usage (int status)
#endif /* ENABLE_SUBIDS */ #endif /* ENABLE_SUBIDS */
#ifdef WITH_SELINUX #ifdef WITH_SELINUX
(void) fputs (_(" -Z, --selinux-user SEUSER new SELinux user mapping for the user account\n"), usageout); (void) fputs (_(" -Z, --selinux-user SEUSER new SELinux user mapping for the user account\n"), usageout);
(void) fputs (_(" --selinux-range SERANGE new SELinux MLS range for the user account\n"), usageout);
#endif /* WITH_SELINUX */ #endif /* WITH_SELINUX */
(void) fputs ("\n", usageout); (void) fputs ("\n", usageout);
exit (status); exit (status);
@ -1004,7 +1006,8 @@ static void process_flags (int argc, char **argv)
{"del-subgids", required_argument, NULL, 'W'}, {"del-subgids", required_argument, NULL, 'W'},
#endif /* ENABLE_SUBIDS */ #endif /* ENABLE_SUBIDS */
#ifdef WITH_SELINUX #ifdef WITH_SELINUX
{"selinux-user", required_argument, NULL, 'Z'}, {"selinux-user", required_argument, NULL, 'Z'},
{"selinux-range", required_argument, NULL, 202},
#endif /* WITH_SELINUX */ #endif /* WITH_SELINUX */
{NULL, 0, NULL, '\0'} {NULL, 0, NULL, '\0'}
}; };
@ -1214,6 +1217,9 @@ static void process_flags (int argc, char **argv)
exit (E_BAD_ARG); exit (E_BAD_ARG);
} }
break; break;
case 202:
user_selinux_range = optarg;
break;
#endif /* WITH_SELINUX */ #endif /* WITH_SELINUX */
default: default:
usage (E_USAGE); usage (E_USAGE);
@ -1354,6 +1360,15 @@ static void process_flags (int argc, char **argv)
usage (E_USAGE); usage (E_USAGE);
} }
#ifdef WITH_SELINUX
if (user_selinux_range && !Zflg) {
fprintf (stderr,
_("%s: %s flag is only allowed with the %s flag\n"),
Prog, "--selinux-range", "--selinux-user");
usage (E_USAGE);
}
#endif /* WITH_SELINUX */
if (user_newid == user_id) { if (user_newid == user_id) {
uflg = false; uflg = false;
oflg = false; oflg = false;
@ -2304,7 +2319,7 @@ int main (int argc, char **argv)
#ifdef WITH_SELINUX #ifdef WITH_SELINUX
if (Zflg) { if (Zflg) {
if ('\0' != *user_selinux) { if ('\0' != *user_selinux) {
if (set_seuser (user_name, user_selinux) != 0) { if (set_seuser (user_name, user_selinux, user_selinux_range) != 0) {
fprintf (stderr, fprintf (stderr,
_("%s: warning: the user name %s to %s SELinux user mapping failed.\n"), _("%s: warning: the user name %s to %s SELinux user mapping failed.\n"),
Prog, user_name, user_selinux); Prog, user_name, user_selinux);