sulogin.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * Mini sulogin implementation for busybox
  4. *
  5. * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  6. */
  7. //config:config SULOGIN
  8. //config: bool "sulogin (18 kb)"
  9. //config: default y
  10. //config: select FEATURE_SYSLOG
  11. //config: help
  12. //config: sulogin is invoked when the system goes into single user
  13. //config: mode (this is done through an entry in inittab).
  14. //applet:IF_SULOGIN(APPLET_NOEXEC(sulogin, sulogin, BB_DIR_SBIN, BB_SUID_DROP, sulogin))
  15. //kbuild:lib-$(CONFIG_SULOGIN) += sulogin.o
  16. //usage:#define sulogin_trivial_usage
  17. //usage: "[-t N] [TTY]"
  18. //usage:#define sulogin_full_usage "\n\n"
  19. //usage: "Single user login\n"
  20. //usage: "\n -p Start a login shell"
  21. //usage: "\n -t SEC Timeout"
  22. #include "libbb.h"
  23. #include <syslog.h>
  24. int sulogin_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  25. int sulogin_main(int argc UNUSED_PARAM, char **argv)
  26. {
  27. int tsid;
  28. int timeout = 0;
  29. unsigned opts;
  30. struct passwd *pwd;
  31. const char *shell;
  32. /* Note: sulogin is not a suid app. It is meant to be run by init
  33. * for single user / emergency mode. init starts it as root.
  34. * Normal users (potentially malicious ones) can only run it under
  35. * their UID, therefore no paranoia here is warranted:
  36. * $LD_LIBRARY_PATH in env, TTY = /dev/sda
  37. * are no more dangerous here than in e.g. cp applet.
  38. */
  39. logmode = LOGMODE_BOTH;
  40. openlog(applet_name, 0, LOG_AUTH);
  41. opts = getopt32(argv, "pt:+", &timeout);
  42. argv += optind;
  43. if (argv[0]) {
  44. close(0);
  45. close(1);
  46. dup(xopen(argv[0], O_RDWR));
  47. close(2);
  48. dup(0);
  49. }
  50. pwd = getpwuid(0);
  51. if (!pwd) {
  52. bb_simple_error_msg_and_die("no password entry for root");
  53. }
  54. while (1) {
  55. int r;
  56. r = ask_and_check_password_extended(pwd, timeout,
  57. "Give root password for maintenance\n"
  58. "(or type Ctrl-D to continue): "
  59. );
  60. if (r < 0) {
  61. /* ^D, ^C, timeout, or read error */
  62. /* util-linux 2.36.1 compat: no message */
  63. /*bb_simple_info_msg("normal startup");*/
  64. return 0;
  65. }
  66. if (r > 0) {
  67. break;
  68. }
  69. pause_after_failed_login();
  70. bb_simple_info_msg("Login incorrect");
  71. }
  72. /* util-linux 2.36.1 compat: no message */
  73. /*bb_simple_info_msg("starting shell for system maintenance");*/
  74. IF_SELINUX(renew_current_security_context());
  75. shell = getenv("SUSHELL");
  76. if (!shell)
  77. shell = getenv("sushell");
  78. if (!shell)
  79. shell = pwd->pw_shell;
  80. /* util-linux 2.36.1 compat: cd to root's HOME, set a few envvars */
  81. setup_environment(shell, 0
  82. + SETUP_ENV_CHANGEENV_LOGNAME
  83. + SETUP_ENV_CHDIR
  84. , pwd);
  85. // no SETUP_ENV_CLEARENV
  86. // SETUP_ENV_CHANGEENV_LOGNAME - set HOME, SHELL, USER,and LOGNAME
  87. // SETUP_ENV_CHDIR - cd to $HOME
  88. /* util-linux 2.36.1 compat: steal ctty if we don't have it yet
  89. * (yes, util-linux uses force=1) */
  90. tsid = tcgetsid(STDIN_FILENO);
  91. if (tsid < 0 || getpid() != tsid) {
  92. if (ioctl(STDIN_FILENO, TIOCSCTTY, /*force:*/ (long)1) != 0) {
  93. // bb_perror_msg("TIOCSCTTY1 tsid:%d", tsid);
  94. if (setsid() > 0) {
  95. // bb_error_msg("done setsid()");
  96. /* If it still does not work, ignore */
  97. if (ioctl(STDIN_FILENO, TIOCSCTTY, /*force:*/ (long)1) != 0) {
  98. // bb_perror_msg("TIOCSCTTY2 tsid:%d", tsid);
  99. }
  100. }
  101. }
  102. }
  103. /*
  104. * Note: login does this (should we do it too?):
  105. */
  106. /*signal(SIGINT, SIG_DFL);*/
  107. /* Exec shell with no additional parameters. Never returns. */
  108. exec_shell(shell, /* -p? then shell is login:*/(opts & 1), NULL);
  109. }