/* vi: set sw=4 ts=4: */ /* * vlock implementation for busybox * * Copyright (C) 2000 by spoon * Written by spoon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /* Shoutz to Michael K. Johnson , author of the * original vlock. I snagged a bunch of his code to write this * minimalistic vlock. */ /* Fixed by Erik Andersen to do passwords the tinylogin way... * It now works with md5, sha1, etc passwords. */ #include #include #include #include #include #include #include #include #include #include #include "busybox.h" static struct passwd *pw; static struct vt_mode ovtm; static struct termios oterm; static int vfd; static int o_lock_all = 0; #ifdef CONFIG_FEATURE_SHADOWPASSWDS static struct spwd *spw; /* getspuid - get a shadow entry by uid */ struct spwd *getspuid(uid_t uid) { struct spwd *sp; struct passwd *mypw; if ((mypw = getpwuid(getuid())) == NULL) { return (NULL); } setspent(); while ((sp = getspent()) != NULL) { if (strcmp(mypw->pw_name, sp->sp_namp) == 0) break; } endspent(); return (sp); } #endif static void release_vt(int signo) { if (!o_lock_all) ioctl(vfd, VT_RELDISP, 1); else ioctl(vfd, VT_RELDISP, 0); } static void acquire_vt(int signo) { ioctl(vfd, VT_RELDISP, VT_ACKACQ); } static void restore_terminal(void) { ioctl(vfd, VT_SETMODE, &ovtm); tcsetattr(STDIN_FILENO, TCSANOW, &oterm); } extern int vlock_main(int argc, char **argv) { sigset_t sig; struct sigaction sa; struct vt_mode vtm; int times = 0; struct termios term; if (argc > 2) { bb_show_usage(); } if (argc == 2) { if (strncmp(argv[1], "-a", 2)) { bb_show_usage(); } else { o_lock_all = 1; } } if ((pw = getpwuid(getuid())) == NULL) { bb_error_msg_and_die("no password for uid %d\n", getuid()); } #ifdef CONFIG_FEATURE_SHADOWPASSWDS if ((strcmp(pw->pw_passwd, "x") == 0) || (strcmp(pw->pw_passwd, "*") == 0)) { if ((spw = getspuid(getuid())) == NULL) { bb_error_msg_and_die("could not read shadow password for uid %d: %s\n", getuid(), strerror(errno)); } if (spw->sp_pwdp) { pw->pw_passwd = spw->sp_pwdp; } } #endif /* CONFIG_FEATURE_SHADOWPASSWDS */ if (pw->pw_passwd[0] == '!' || pw->pw_passwd[0] == '*') { bb_error_msg_and_die("Account disabled for uid %d\n", getuid()); } /* we no longer need root privs */ setuid(getuid()); setgid(getgid()); if ((vfd = open("/dev/tty", O_RDWR)) < 0) { bb_error_msg_and_die("/dev/tty"); }; if (ioctl(vfd, VT_GETMODE, &vtm) < 0) { bb_error_msg_and_die("/dev/tty"); }; /* 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); ovtm = vtm; vtm.mode = VT_PROCESS; vtm.relsig = SIGUSR1; vtm.acqsig = SIGUSR2; ioctl(vfd, VT_SETMODE, &vtm); 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 { char *pass, *crypt_pass; char prompt[100]; if (o_lock_all) { printf("All Virtual Consoles locked.\n"); } else { printf("This Virtual Console locked.\n"); } fflush(stdout); snprintf(prompt, 100, "%s's password: ", pw->pw_name); if ((pass = getpass(prompt)) == NULL) { perror("getpass"); restore_terminal(); exit(1); } crypt_pass = pw_encrypt(pass, pw->pw_passwd); if (strncmp(crypt_pass, pw->pw_passwd, sizeof(crypt_pass)) == 0) { memset(pass, 0, strlen(pass)); memset(crypt_pass, 0, strlen(crypt_pass)); restore_terminal(); return 0; } memset(pass, 0, strlen(pass)); memset(crypt_pass, 0, strlen(crypt_pass)); if (isatty(STDIN_FILENO) == 0) { perror("isatty"); restore_terminal(); exit(1); } sleep(++times); printf("Password incorrect.\n"); if (times >= 3) { sleep(15); times = 2; } } while (1); } /* Local Variables: c-file-style: "linux" c-basic-offset: 4 tab-width: 4 End: */