diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-14 19:33:34 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-14 19:33:34 +0000 |
commit | 1272be04be0cb803eec87f602edb2e3e6f111aea (patch) | |
tree | bce17f6478cdd9f3c4ec3d751135dc42786d6a56 /login-utils/sulogin.c | |
parent | Releasing progress-linux version 2.39.3-11~progress7.99u1. (diff) | |
download | util-linux-1272be04be0cb803eec87f602edb2e3e6f111aea.tar.xz util-linux-1272be04be0cb803eec87f602edb2e3e6f111aea.zip |
Merging upstream version 2.40.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'login-utils/sulogin.c')
-rw-r--r-- | login-utils/sulogin.c | 184 |
1 files changed, 151 insertions, 33 deletions
diff --git a/login-utils/sulogin.c b/login-utils/sulogin.c index 45a558d..2682c30 100644 --- a/login-utils/sulogin.c +++ b/login-utils/sulogin.c @@ -99,6 +99,81 @@ static int locked_account_password(const char * const passwd) return 0; } +#ifdef HAVE_LIBSELINUX +/* + * Cached check whether SELinux is enabled. + */ +static int is_selinux_enabled_cached(void) +{ + static int cache = -1; + + if (cache == -1) + cache = is_selinux_enabled(); + + return cache; +} + +/* Computed SELinux login context. */ +static char *login_context; + +/* + * Compute SELinux login context. + */ +static void compute_login_context(void) +{ + char *seuser = NULL; + char *level = NULL; + + if (is_selinux_enabled_cached() == 0) + goto cleanup; + + if (getseuserbyname("root", &seuser, &level) == -1) { + warnx(_("failed to compute seuser")); + goto cleanup; + } + + if (get_default_context_with_level(seuser, level, NULL, &login_context) == -1) { + warnx(_("failed to compute default context")); + goto cleanup; + } + +cleanup: + free(seuser); + free(level); +} + +/* + * Compute SELinux terminal context. + */ +static void tcinit_selinux(struct console *con) +{ + security_class_t tclass; + + if (!login_context) + return; + + if (fgetfilecon(con->fd, &con->reset_tty_context) == -1) { + warn(_("failed to get context of terminal %s"), con->tty); + return; + } + + tclass = string_to_security_class("chr_file"); + if (tclass == 0) { + warnx(_("security class chr_file not available")); + freecon(con->reset_tty_context); + con->reset_tty_context = NULL; + return; + } + + if (security_compute_relabel(login_context, con->reset_tty_context, tclass, &con->user_tty_context) == -1) { + warnx(_("failed to compute relabel context of terminal")); + freecon(con->reset_tty_context); + con->reset_tty_context = NULL; + return; + } +} +#endif + /* * Fix the tty modes and set reasonable defaults. */ @@ -132,6 +207,10 @@ static void tcinit(struct console *con) errno = 0; #endif +#ifdef HAVE_LIBSELINUX + tcinit_selinux(con); +#endif + #ifdef TIOCGSERIAL if (ioctl(fd, TIOCGSERIAL, &serinfo) >= 0) con->flags |= CON_SERIAL; @@ -270,23 +349,21 @@ static void tcfinal(struct console *con) { struct termios *tio = &con->tio; const int fd = con->fd; + char *term, *ttyname = NULL; - if (con->flags & CON_EIO) - return; - if ((con->flags & CON_SERIAL) == 0) { - xsetenv("TERM", "linux", 0); - return; + if (con->tty) + ttyname = strncmp(con->tty, "/dev/", 5) == 0 ? + con->tty + 5 : con->tty; + + term = get_terminal_default_type(ttyname, con->flags & CON_SERIAL); + if (term) { + xsetenv("TERM", term, 0); + free(term); } - if (con->flags & CON_NOTTY) { - xsetenv("TERM", "dumb", 0); + + if (!(con->flags & CON_SERIAL) || (con->flags & CON_NOTTY)) return; - } -#if defined (__s390__) || defined (__s390x__) - xsetenv("TERM", "dumb", 0); -#else - xsetenv("TERM", "vt102", 0); -#endif tio->c_iflag |= (IXON | IXOFF); tio->c_lflag |= (ICANON | ISIG | ECHO|ECHOE|ECHOK|ECHOKE); tio->c_oflag |= OPOST; @@ -787,7 +864,7 @@ out: /* * Password was OK, execute a shell. */ -static void sushell(struct passwd *pwd) +static void sushell(struct passwd *pwd, struct console *con) { char shell[PATH_MAX]; char home[PATH_MAX]; @@ -844,22 +921,21 @@ static void sushell(struct passwd *pwd) mask_signal(SIGHUP, SIG_DFL, NULL); #ifdef HAVE_LIBSELINUX - if (is_selinux_enabled() > 0) { - char *scon = NULL; - char *seuser = NULL; - char *level = NULL; - - if (getseuserbyname("root", &seuser, &level) == 0) { - if (get_default_context_with_level(seuser, level, 0, &scon) == 0) { - if (setexeccon(scon) != 0) - warnx(_("setexeccon failed")); - freecon(scon); - } + if (is_selinux_enabled_cached() == 1) { + if (con->user_tty_context) { + if (fsetfilecon(con->fd, con->user_tty_context) == -1) + warn(_("failed to set context to %s for terminal %s"), con->user_tty_context, con->tty); + } + + if (login_context) { + if (setexeccon(login_context) == -1) + warn(_("failed to set exec context to %s"), login_context); } - free(seuser); - free(level); } +#else + (void)con; #endif + execl(su_shell, shell, (char *)NULL); warn(_("failed to execute %s"), su_shell); @@ -868,6 +944,30 @@ static void sushell(struct passwd *pwd) warn(_("failed to execute %s"), "/bin/sh"); } +#ifdef HAVE_LIBSELINUX +static void tcreset_selinux(struct list_head *consoles) { + struct list_head *ptr; + struct console *con; + + if (is_selinux_enabled_cached() == 0) + return; + + list_for_each(ptr, consoles) { + con = list_entry(ptr, struct console, entry); + + if (con->fd < 0) + continue; + if (!con->reset_tty_context) + continue; + if (fsetfilecon(con->fd, con->reset_tty_context) == -1) + warn(_("failed to reset context to %s for terminal %s"), con->reset_tty_context, con->tty); + + freecon(con->reset_tty_context); + con->reset_tty_context = NULL; + } +} +#endif + static void usage(void) { FILE *out = stdout; @@ -885,8 +985,8 @@ static void usage(void) out); fputs(USAGE_SEPARATOR, out); - printf(USAGE_HELP_OPTIONS(26)); - printf(USAGE_MAN_TAIL("sulogin(8)")); + fprintf(out, USAGE_HELP_OPTIONS(26)); + fprintf(out, USAGE_MAN_TAIL("sulogin(8)")); exit(EXIT_SUCCESS); } @@ -1017,6 +1117,10 @@ int main(int argc, char **argv) return EXIT_FAILURE; } +#ifdef HAVE_LIBSELINUX + compute_login_context(); +#endif + /* * Ask for the password on the consoles. */ @@ -1036,9 +1140,18 @@ int main(int argc, char **argv) } ptr = (&consoles)->next; - if (ptr->next == &consoles) { - con = list_entry(ptr, struct console, entry); - goto nofork; +#ifdef HAVE_LIBSELINUX + /* + * Always fork with SELinux enabled, so the parent can restore the + * terminal context afterwards. + */ + if (is_selinux_enabled_cached() == 0) +#endif + { + if (ptr->next == &consoles) { + con = list_entry(ptr, struct console, entry); + goto nofork; + } } @@ -1089,7 +1202,7 @@ int main(int argc, char **argv) #endif if (doshell) { /* sushell() unmask signals */ - sushell(pwd); + sushell(pwd, con); mask_signal(SIGQUIT, SIG_IGN, &saved_sigquit); mask_signal(SIGTSTP, SIG_IGN, &saved_sigtstp); @@ -1195,5 +1308,10 @@ int main(int argc, char **argv) } while (1); mask_signal(SIGCHLD, SIG_DFL, NULL); + +#ifdef HAVE_LIBSELINUX + tcreset_selinux(&consoles); +#endif + return EXIT_SUCCESS; } |