busybox/loginutils/vlock.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * vlock implementation for busybox
   4 *
   5 * Copyright (C) 2000 by spoon <spoon@ix.netcom.com>
   6 * Written by spoon <spon@ix.netcom.com>
   7 *
   8 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
   9 */
  10
  11/* Shoutz to Michael K. Johnson <johnsonm@redhat.com>, author of the
  12 * original vlock.  I snagged a bunch of his code to write this
  13 * minimalistic vlock.
  14 */
  15/* Fixed by Erik Andersen to do passwords the tinylogin way...
  16 * It now works with md5, sha1, etc passwords.
  17 */
  18//config:config VLOCK
  19//config:       bool "vlock (17 kb)"
  20//config:       default y
  21//config:       help
  22//config:       Build the "vlock" applet which allows you to lock (virtual) terminals.
  23//config:
  24//config:       Note that busybox binary must be setuid root for this applet to
  25//config:       work properly.
  26
  27//applet:/* Needs to be run by root or be suid root - needs to change uid and gid: */
  28//applet:IF_VLOCK(APPLET(vlock, BB_DIR_USR_BIN, BB_SUID_REQUIRE))
  29
  30//kbuild:lib-$(CONFIG_VLOCK) += vlock.o
  31
  32//usage:#define vlock_trivial_usage
  33//usage:       "[-a]"
  34//usage:#define vlock_full_usage "\n\n"
  35//usage:       "Lock a virtual terminal. A password is required to unlock.\n"
  36//usage:     "\n        -a      Lock all VTs"
  37
  38#include "libbb.h"
  39
  40#ifdef __linux__
  41#include <sys/vt.h>
  42
  43static void release_vt(int signo UNUSED_PARAM)
  44{
  45        /* If -a, param is 0, which means:
  46         * "no, kernel, we don't allow console switch away from us!" */
  47        ioctl(STDIN_FILENO, VT_RELDISP, (unsigned long) !option_mask32);
  48}
  49
  50static void acquire_vt(int signo UNUSED_PARAM)
  51{
  52        /* ACK to kernel that switch to console is successful */
  53        ioctl(STDIN_FILENO, VT_RELDISP, VT_ACKACQ);
  54}
  55#endif
  56
  57int vlock_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  58int vlock_main(int argc UNUSED_PARAM, char **argv)
  59{
  60#ifdef __linux__
  61        struct vt_mode vtm;
  62        struct vt_mode ovtm;
  63#endif
  64        struct termios term;
  65        struct termios oterm;
  66        struct passwd *pw;
  67
  68        pw = xgetpwuid(getuid());
  69        getopt32(argv, "^" "a" "\0" "=0"/* no args!*/);
  70
  71        /* Ignore some signals so that we don't get killed by them */
  72        bb_signals(0
  73                + (1 << SIGTSTP)
  74                + (1 << SIGTTIN)
  75                + (1 << SIGTTOU)
  76                + (1 << SIGHUP )
  77                + (1 << SIGCHLD) /* paranoia :) */
  78                + (1 << SIGQUIT)
  79                + (1 << SIGINT )
  80                , SIG_IGN);
  81
  82#ifdef __linux__
  83        /* We will use SIGUSRx for console switch control: */
  84        /* 1: set handlers */
  85        signal_SA_RESTART_empty_mask(SIGUSR1, release_vt);
  86        signal_SA_RESTART_empty_mask(SIGUSR2, acquire_vt);
  87        /* 2: unmask them */
  88        sig_unblock(SIGUSR1);
  89        sig_unblock(SIGUSR2);
  90#endif
  91
  92        /* Revert stdin/out to our controlling tty
  93         * (or die if we have none) */
  94        xmove_fd(xopen(CURRENT_TTY, O_RDWR), STDIN_FILENO);
  95        xdup2(STDIN_FILENO, STDOUT_FILENO);
  96
  97#ifdef __linux__
  98        xioctl(STDIN_FILENO, VT_GETMODE, &vtm);
  99        ovtm = vtm;
 100        /* "console switches are controlled by us, not kernel!" */
 101        vtm.mode = VT_PROCESS;
 102        vtm.relsig = SIGUSR1;
 103        vtm.acqsig = SIGUSR2;
 104        ioctl(STDIN_FILENO, VT_SETMODE, &vtm);
 105#endif
 106
 107//TODO: use set_termios_to_raw()
 108        tcgetattr(STDIN_FILENO, &oterm);
 109        term = oterm;
 110        term.c_iflag |= IGNBRK; /* ignore serial break (why? VTs don't have breaks, right?) */
 111        term.c_iflag &= ~BRKINT; /* redundant? "dont translate break to SIGINT" */
 112        term.c_lflag &= ~(ISIG | ECHO | ECHOCTL); /* ignore ^C ^Z, echo off */
 113        tcsetattr_stdin_TCSANOW(&term);
 114
 115        while (1) {
 116                printf("Virtual console%s locked by %s.\n",
 117                                /* "s" if -a, else "": */ "s" + !option_mask32,
 118                                pw->pw_name
 119                );
 120                if (ask_and_check_password(pw) > 0) {
 121                        break;
 122                }
 123                bb_do_delay(LOGIN_FAIL_DELAY);
 124                puts("Incorrect password");
 125        }
 126
 127#ifdef __linux__
 128        ioctl(STDIN_FILENO, VT_SETMODE, &ovtm);
 129#endif
 130        tcsetattr_stdin_TCSANOW(&oterm);
 131        fflush_stdout_and_exit(EXIT_SUCCESS);
 132}
 133