/* sulogin.c - Single User Login. * * Copyright 2014 Ashish Kumar Gupta <ashishkguptaiit.cse@gmail.com> * Copyright 2014 Kyungwan Han <asura321@gmail.com> * * * Relies on libcrypt for hash calculation. * No support for PAM/securetty/selinux/login script/issue/utmp USE_SULOGIN(NEWTOY(sulogin, "t#<0=0", TOYFLAG_SBIN|TOYFLAG_NEEDROOT)) config SULOGIN bool "sulogin" default n depends on TOYBOX_SHADOW help usage: sulogin [-t time] [tty] Single User Login. -t Default Time for Single User Login */ #define FOR_sulogin #include "toys.h" GLOBALS( long timeout; struct termios crntio; ) static void timeout_handle(int signo) { tcsetattr(0, TCSANOW, &(TT.crntio)); fflush(stdout); xprintf("\n Timed out - Normal startup\n"); exit(0); } static int validate_password(char *pwd) { struct sigaction sa; int ret; char *s = "Give root password for system maintenance\n" "(or type Control-D for normal startup):", *pass; tcgetattr(0, &(TT.crntio)); sa.sa_handler = timeout_handle; if(TT.timeout) { sigaction(SIGALRM, &sa, NULL); alarm(TT.timeout); } ret = read_password(toybuf, sizeof(toybuf), s); if(TT.timeout) alarm(0); if ( ret && !toybuf[0]) { xprintf("Normal startup.\n"); return -1; } pass = crypt(toybuf, pwd); ret = 1; if( pass && !strcmp(pass, pwd)) ret = 0; return ret; } static void run_shell(char *shell) { snprintf(toybuf,sizeof(toybuf), "-%s", shell); execl(shell, toybuf, NULL); error_exit("Failed to spawn shell"); } void sulogin_main(void) { struct passwd *pwd = NULL; struct spwd * spwd = NULL; char *forbid[] = { "BASH_ENV", "ENV", "HOME", "IFS", "LD_LIBRARY_PATH", "LD_PRELOAD", "LD_TRACE_LOADED_OBJECTS", "LD_BIND_NOW", "LD_AOUT_LIBRARY_PATH", "LD_AOUT_PRELOAD", "LD_NOWARN", "LD_KEEPDIR", "SHELL", NULL }; char *shell = NULL, *pass = NULL, **temp = forbid; if (toys.optargs[0]) { int fd; dup2((fd = xopen(toys.optargs[0], O_RDWR)), 0); if (!isatty(0)) error_exit("%s: it is not a tty", toys.optargs[0]); dup2( fd, 1); dup2( fd, 2); if (fd > 2) close(fd); } for (temp = forbid; *temp; temp++) unsetenv(*temp); if (!(pwd = getpwuid(0))) error_exit("invalid user"); pass = pwd->pw_passwd; if ((pass[0] == 'x' || pass[0] == '*') && !pass[1]) { if ((spwd = getspnam (pwd->pw_name))) pass = spwd->sp_pwdp; } while (1) { int r = validate_password(pass); if (r == 1) xprintf("Incorrect Login.\n"); else if (r == 0) break; else if (r == -1) return; } if ((shell = getenv("SUSHELL")) || (shell = getenv("sushell")) || (shell = pwd->pw_shell)) run_shell((shell && *shell)? shell: "/bin/sh"); }