Example: /* w00w00! */ /* CAP - Console Access Protection */ /* This provides security from phsyical access to your conoles. */ /* When you run this program, it will clear the screen and prompt */ /* for a password. After so many failed attempts it will lock the */ /* tty and not allow them to try anymore. While this program is */ /* running, they can't abort this program, and they can not switch */ /* consoles either. The only only way around this is to reboot the */ /* computer, in which case it will be obvious that someone tried to */ /* access your server's consoles. This will log the date and time */ /* the person tried to get access into your console. */ /* */ /* Compile: [g]cc -o CAP CAP.c -ltermcap */ /* If you have shadow passwords compile with -DUSESHADOW. */ /* To compile in debug (or testing) mode, compile with -DDEBUG. */ /* */ /* Shok (Matt Conover), shok@dataforce.net */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef DEBUG #define SIGSEGV 11 /* SIGSEGV == sig # 11 */ #endif #define ERROR -1 #define SAME 0 #define LOCKOUT 3 /* How long in minutes to lock out of the console. */ #define MAXFAIL 3 /* Number of times they can enter an invalid password. */ /* before being locked out for LOCKOUT minutes. */ /* Used to disable switching consoles. */ #define LOCKVT(x) if ((ioctl(fd, VT_LOCKSWITCH, 1)) == ERROR) { \ perror("locking console (/dev/tty/)"); \ exit(ERROR); \ } /* Used to reenable ability to switch consoles. */ #define UNLOCKVT(x) if ((ioctl(fd, VT_UNLOCKSWITCH, 1)) == ERROR) { \ perror("locking console (/dev/tty/)"); \ exit(ERROR); \ } int fd; /* Console fd. */ char *strip(char *str); /* Used to strip newlines from ctime(). */ #ifdef DEBUG void sighandler(int signum); #endif DEBUG void main() { int uid; int failed = 0; /* Number of failed attempts out of MAXFAIL. */ int totfailed = 0; /* Number of total failed attempts (not reseted). */ time_t tm; char curtime[64]; /* Don't change passwd or realpasswd's length. This is the maximum */ /* password length allow from getpass(). Any smaller can overflow. */ char *pass, passwd[128], realpasswd[128]; struct passwd *pwd; #ifdef USESHADOW struct spwd *spwd; #endif if ((fd = open("/dev/tty", O_RDWR)) == ERROR) { perror("opening console (/dev/tty)"); exit(ERROR); } /* Disable signals (so attackers can't abort program). */ #ifndef DEBUG signal(SIGHUP, SIG_IGN); signal(SIGINT, SIG_IGN); signal(SIGTERM, SIG_IGN); signal(SIGQUIT, SIG_IGN); signal(SIGTSTP, SIG_IGN); #else signal(SIGINT, sighandler); signal(SIGTERM, sighandler); signal(SIGQUIT, sighandler); signal(SIGTSTP, sighandler); signal(SIGSEGV, sighandler); #endif LOCKVT(fd); /* Lock the VT. It can no longer switch. */ uid = getuid(); pwd = getpwuid(uid); #ifdef USESHADOW if ((spwd = getspnam(pwd->pw_name)) == NULL) { perror("getspnam"); exit(ERROR); } strncpy(realpasswd, spwd->sp_pwdp, sizeof(realpasswd)); #else strncpy(realpasswd, pwd->pw_passwd, sizeof(realpasswd)); #endif clr(); /* clear the screen */ printf("w00w00!\n"); printf("Console is now locked.\n"); getchar(); /* Used to log invalid password attempts. */ openlog("CAP/conprot", LOG_CONS, LOG_AUTHPRIV); while (1) { /* Get the password from the user. */ pass = getpass("Enter password: "); /* Encrypt the password from getpass(). /* Note, we are using realpasswd for our salt. This is to allow a */ /* salt of any size. This also saving us the trouble of getting */ /* the salt ourselves. */ strncpy(passwd, crypt(pass, realpasswd), sizeof(passwd)); passwd[128] = '\0'; /* NULL terminate passwd just to be safe. */ #ifdef DEBUG printf("Encrypted password from user: %s\n", passwd); printf("The real encrypted password: %s\n", realpasswd); #endif if ((strcmp(passwd, realpasswd)) == SAME) { /* Unlock the console, to allow it to switch. */ UNLOCKVT(fd); closelog(); /* Close logging. */ clr(); printf("Everything is now restored.\n"); if (totfailed == 0) printf("No one tried to access the console.\n"); else printf("Total number of failed attempts to unlock console: %d\n", totfailed); exit(0); } else { failed++, totfailed++; /* Increase number of failed attempts. */ /* Log bad attempts to syslog. */ tm = time(NULL); snprintf(curtime, sizeof(curtime), (char *)ctime(&tm)); strip(curtime); /* Strip new lines out of the time. */ syslog(LOG_WARNING, "Failed access attempt on: %s", curtime); printf("Invalid password.\n"); if (failed >= MAXFAIL) { printf("Maximum number of failed attempts.\n" "Now locking for %d minutes.\n", LOCKOUT); sleep(LOCKOUT * 60); /* Convert the minutes to seconds. */ failed = 0; /* Reset the number of failed attempts. */ } } } } char *strip(char *str) { register int i; for (i = 0; str[i]; i++) /* Strip newline out of string. */ /* We do this because syslog appends the newline itself. */ if (str[i] == '\n') str[i] = '\0'; return str; } #ifdef DEBUG void sighandler(int signum) { if (signum == SIGSEGV) printf("Received SIGSEGV.\n"); printf("\nAborting and unlocking console.\n"); UNLOCKVT(fd); if (signum == 11) kill(getpid(), 11); exit(0); } #endif /* Clear the screen usning termcap */ clr() { char *clear; char clbuf[1024], *clbp = clbuf; if (tgetent(clbuf, getenv("TERM")) == ERROR) { perror("tgetent"); system("clear"); return; } if ((clear = tgetstr("cl", &clbp)) == NULL) { perror("tgetent"); system("clear"); return; } if (clear) tputs(clear, tgetnum("li"), putchar); }