vlock.c 3.6 KB

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