/*
 * conslock: lock a console
 *
 * By Patrick Reynolds (reynolds .at. cs duke edu) and distributed under GPL.
 *
 * Ported by Brian Clarke (9/6/2000) to build/run on other 'nixes (Solaris &
 * AIX have been tested)
 *
 *
 * To install it:
 *   #define or #undef SPWD, below.
 *   make
 * If you use a shadow system:
 *   chown root.root conslock ; chmod 4711 conslock
 * or whatever it takes to let it read /etc/shadow
 *
 * To run it, just type
 *   conslock
 */

/* If you have shadow passwords (and you should!), define this */
#define SPWD

#include <crypt.h>
#include <pwd.h>
#include <stdio.h>
#include <strings.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>

#ifdef SPWD
#include <shadow.h>
#endif

#ifndef linux
#include <termios.h>
#include <fcntl.h>
struct termios tty_info;
struct termios orig;
int term;
#endif

void locktty(int lock);

int main() {
  char *tmp;
  struct passwd *pw;
#ifdef SPWD
  struct spwd *spw;
#endif

#ifndef linux
  if ((term = open("/dev/tty", O_RDWR)) == -1) {
    perror("open()");
    exit(0);
  }

  if (tcgetattr(term, &tty_info)) {
    perror("tcgetattr()");
    exit(0);
  }
  memcpy(&orig, &tty_info, sizeof(struct termios));
#endif

  if (!(pw = getpwuid(getuid()))) {
    printf("UID not found.\n");
    return -1;
  }
  if (!pw->pw_passwd[0]) {
    printf("UID has no password.\n");
    return -1;
  }

#ifdef SPWD
  if (!(spw = getspnam(pw->pw_name))) {
    printf("Cannot open /etc/shadow.\n");
    return -1;
  }
#endif

  locktty(1);
  printf("\ntty locked.  Enter %s's password to unlock it.\n", pw->pw_name);
  do {
    tmp = (char *)getpass("password: ");
#ifdef SPWD
  } while (strcmp(spw->sp_pwdp, crypt(tmp, spw->sp_pwdp)));
#else
  } while (strcmp(pw->pw_passwd, crypt(tmp, pw->pw_passwd)));
#endif
  bzero(tmp, strlen(tmp));

  locktty(0);

#ifndef linux
  tcsetattr(term, TCSANOW, &orig);
  close(term);
#endif

  return 0;
}

void locktty(int lock) {
  static mode_t oldttymode = 0;
  static char *buf = NULL;

  if (!lock && !oldttymode)
    return;  /* tty was never locked */

  if (!buf) {
    if (!isatty(0)) return;
    if (!(buf = ttyname(0))) return;
  }

  if (!lock) {
    chmod(buf, oldttymode);
    oldttymode = 0;
    return;
  }

#ifndef linux
  tty_info.c_lflag &= ~ISIG;
  tcsetattr(term, TCSANOW, &tty_info);
#endif

  {
    struct stat stat_buf;
    stat(buf, &stat_buf);
    oldttymode = stat_buf.st_mode;
  }

  chmod(buf, oldttymode & ~022);
}
