X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=loginutils%2Fvlock.c;h=5ba6a8780d610046148b47e6eb5fe37e4730091a;hb=5b2cc0aaee6985431d9bab1b49ceea7e1fa1d7af;hp=7a44d94054d216423c1ddf775ff8b04004ab5d4f;hpb=e1a0d486e4804eae098571f1a6788394c2ee51ae;p=oweals%2Fbusybox.git diff --git a/loginutils/vlock.c b/loginutils/vlock.c index 7a44d9405..5ba6a8780 100644 --- a/loginutils/vlock.c +++ b/loginutils/vlock.c @@ -1,12 +1,11 @@ /* vi: set sw=4 ts=4: */ - /* * vlock implementation for busybox * * Copyright (C) 2000 by spoon * Written by spoon * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* Shoutz to Michael K. Johnson , author of the @@ -14,107 +13,121 @@ * minimalistic vlock. */ /* Fixed by Erik Andersen to do passwords the tinylogin way... - * It now works with md5, sha1, etc passwords. */ + * It now works with md5, sha1, etc passwords. + */ +//config:config VLOCK +//config: bool "vlock" +//config: default y +//config: help +//config: Build the "vlock" applet which allows you to lock (virtual) terminals. +//config: +//config: Note that Busybox binary must be setuid root for this applet to +//config: work properly. -#include "busybox.h" -#include +//applet:/* Needs to be run by root or be suid root - needs to change uid and gid: */ +//applet:IF_VLOCK(APPLET(vlock, BB_DIR_USR_BIN, BB_SUID_REQUIRE)) -static struct passwd *pw; -static struct vt_mode ovtm; -static struct termios oterm; -static int vfd; -static unsigned long o_lock_all; +//kbuild:lib-$(CONFIG_VLOCK) += vlock.o -static void release_vt(int signo) -{ - if (!o_lock_all) - ioctl(vfd, VT_RELDISP, 1); - else - ioctl(vfd, VT_RELDISP, 0); -} +//usage:#define vlock_trivial_usage +//usage: "[-a]" +//usage:#define vlock_full_usage "\n\n" +//usage: "Lock a virtual terminal. A password is required to unlock.\n" +//usage: "\n -a Lock all VTs" -static void acquire_vt(int signo) +#include "libbb.h" + +#ifdef __linux__ +#include + +static void release_vt(int signo UNUSED_PARAM) { - ioctl(vfd, VT_RELDISP, VT_ACKACQ); + /* If -a, param is 0, which means: + * "no, kernel, we don't allow console switch away from us!" */ + ioctl(STDIN_FILENO, VT_RELDISP, (unsigned long) !option_mask32); } -static void restore_terminal(void) +static void acquire_vt(int signo UNUSED_PARAM) { - ioctl(vfd, VT_SETMODE, &ovtm); - tcsetattr(STDIN_FILENO, TCSANOW, &oterm); + /* ACK to kernel that switch to console is successful */ + ioctl(STDIN_FILENO, VT_RELDISP, VT_ACKACQ); } +#endif -int vlock_main(int argc, char **argv) +int vlock_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int vlock_main(int argc UNUSED_PARAM, char **argv) { - sigset_t sig; - struct sigaction sa; +#ifdef __linux__ struct vt_mode vtm; + struct vt_mode ovtm; +#endif struct termios term; - - if (argc > 2) { - bb_show_usage(); - } - - o_lock_all = getopt32(argc, argv, "a"); - - if((pw = getpwuid(getuid())) == NULL) { - bb_error_msg_and_die("unknown uid %d", getuid()); - } - - vfd = xopen(CURRENT_TTY, O_RDWR); - - if (ioctl(vfd, VT_GETMODE, &vtm) < 0) { - bb_perror_msg_and_die("VT_GETMODE"); - } - - /* mask a bunch of signals */ - sigprocmask(SIG_SETMASK, NULL, &sig); - sigdelset(&sig, SIGUSR1); - sigdelset(&sig, SIGUSR2); - sigaddset(&sig, SIGTSTP); - sigaddset(&sig, SIGTTIN); - sigaddset(&sig, SIGTTOU); - sigaddset(&sig, SIGHUP); - sigaddset(&sig, SIGCHLD); - sigaddset(&sig, SIGQUIT); - sigaddset(&sig, SIGINT); - - sigemptyset(&(sa.sa_mask)); - sa.sa_flags = SA_RESTART; - sa.sa_handler = release_vt; - sigaction(SIGUSR1, &sa, NULL); - sa.sa_handler = acquire_vt; - sigaction(SIGUSR2, &sa, NULL); - - /* need to handle some signals so that we don't get killed by them */ - sa.sa_handler = SIG_IGN; - sigaction(SIGHUP, &sa, NULL); - sigaction(SIGQUIT, &sa, NULL); - sigaction(SIGINT, &sa, NULL); - sigaction(SIGTSTP, &sa, NULL); - + struct termios oterm; + struct passwd *pw; + + pw = xgetpwuid(getuid()); + opt_complementary = "=0"; /* no params! */ + getopt32(argv, "a"); + + /* Ignore some signals so that we don't get killed by them */ + bb_signals(0 + + (1 << SIGTSTP) + + (1 << SIGTTIN) + + (1 << SIGTTOU) + + (1 << SIGHUP ) + + (1 << SIGCHLD) /* paranoia :) */ + + (1 << SIGQUIT) + + (1 << SIGINT ) + , SIG_IGN); + +#ifdef __linux__ + /* We will use SIGUSRx for console switch control: */ + /* 1: set handlers */ + signal_SA_RESTART_empty_mask(SIGUSR1, release_vt); + signal_SA_RESTART_empty_mask(SIGUSR2, acquire_vt); + /* 2: unmask them */ + sig_unblock(SIGUSR1); + sig_unblock(SIGUSR2); +#endif + + /* Revert stdin/out to our controlling tty + * (or die if we have none) */ + xmove_fd(xopen(CURRENT_TTY, O_RDWR), STDIN_FILENO); + xdup2(STDIN_FILENO, STDOUT_FILENO); + +#ifdef __linux__ + xioctl(STDIN_FILENO, VT_GETMODE, &vtm); ovtm = vtm; + /* "console switches are controlled by us, not kernel!" */ vtm.mode = VT_PROCESS; vtm.relsig = SIGUSR1; vtm.acqsig = SIGUSR2; - ioctl(vfd, VT_SETMODE, &vtm); + ioctl(STDIN_FILENO, VT_SETMODE, &vtm); +#endif +//TODO: use set_termios_to_raw() tcgetattr(STDIN_FILENO, &oterm); term = oterm; - term.c_iflag &= ~BRKINT; - term.c_iflag |= IGNBRK; - term.c_lflag &= ~ISIG; - term.c_lflag &= ~(ECHO | ECHOCTL); - tcsetattr(STDIN_FILENO, TCSANOW, &term); - - do { - printf("Virtual Console%s locked by %s.\n", (o_lock_all) ? "s" : "", pw->pw_name); - if (correct_password(pw)) { + term.c_iflag |= IGNBRK; /* ignore serial break (why? VTs don't have breaks, right?) */ + term.c_iflag &= ~BRKINT; /* redundant? "dont translate break to SIGINT" */ + term.c_lflag &= ~(ISIG | ECHO | ECHOCTL); /* ignore ^C ^Z, echo off */ + tcsetattr_stdin_TCSANOW(&term); + + while (1) { + printf("Virtual console%s locked by %s.\n", + /* "s" if -a, else "": */ "s" + !option_mask32, + pw->pw_name + ); + if (ask_and_check_password(pw) > 0) { break; } - bb_do_delay(FAIL_DELAY); - puts("Password incorrect"); - } while (1); - restore_terminal(); - return 0; + bb_do_delay(LOGIN_FAIL_DELAY); + puts("Incorrect password"); + } + +#ifdef __linux__ + ioctl(STDIN_FILENO, VT_SETMODE, &ovtm); +#endif + tcsetattr_stdin_TCSANOW(&oterm); + fflush_stdout_and_exit(EXIT_SUCCESS); }