lock.c revision 231994
11590Srgrimes/* 21590Srgrimes * Copyright (c) 1980, 1987, 1993 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * 51590Srgrimes * This code is derived from software contributed to Berkeley by 61590Srgrimes * Bob Toxen. 71590Srgrimes * 81590Srgrimes * Redistribution and use in source and binary forms, with or without 91590Srgrimes * modification, are permitted provided that the following conditions 101590Srgrimes * are met: 111590Srgrimes * 1. Redistributions of source code must retain the above copyright 121590Srgrimes * notice, this list of conditions and the following disclaimer. 131590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141590Srgrimes * notice, this list of conditions and the following disclaimer in the 151590Srgrimes * documentation and/or other materials provided with the distribution. 161590Srgrimes * 4. Neither the name of the University nor the names of its contributors 171590Srgrimes * may be used to endorse or promote products derived from this software 181590Srgrimes * without specific prior written permission. 191590Srgrimes * 201590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 211590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 221590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 231590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 241590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 251590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 261590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 271590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 281590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 291590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 301590Srgrimes * SUCH DAMAGE. 311590Srgrimes */ 321590Srgrimes 331590Srgrimes#ifndef lint 3427575Scharnierstatic const char copyright[] = 351590Srgrimes"@(#) Copyright (c) 1980, 1987, 1993\n\ 361590Srgrimes The Regents of the University of California. All rights reserved.\n"; 371590Srgrimes#endif /* not lint */ 381590Srgrimes 391590Srgrimes#ifndef lint 4027575Scharnier#if 0 411590Srgrimesstatic char sccsid[] = "@(#)lock.c 8.1 (Berkeley) 6/6/93"; 4227575Scharnier#endif 431590Srgrimes#endif /* not lint */ 4499112Sobrien#include <sys/cdefs.h> 4599112Sobrien__FBSDID("$FreeBSD: head/usr.bin/lock/lock.c 231994 2012-02-22 06:27:20Z kevlo $"); 461590Srgrimes 471590Srgrimes/* 4899709Sdd * Lock a terminal up until the given key is entered or the given 4999709Sdd * interval times out. 501590Srgrimes * 511590Srgrimes * Timeout interval is by default TIMEOUT, it can be changed with 521590Srgrimes * an argument of the form -time where time is in minutes 531590Srgrimes */ 541590Srgrimes 551590Srgrimes#include <sys/param.h> 561590Srgrimes#include <sys/stat.h> 571590Srgrimes#include <sys/time.h> 581590Srgrimes#include <sys/signal.h> 59100806Sdd#include <sys/consio.h> 6027575Scharnier#include <err.h> 61200462Sdelphij#include <ctype.h> 62124824Scperciva#include <errno.h> 63216696Sed#include <paths.h> 6427575Scharnier#include <pwd.h> 65209567Sgavin#include <stdint.h> 661590Srgrimes#include <stdio.h> 6727575Scharnier#include <stdlib.h> 681590Srgrimes#include <string.h> 6952158Snectar#include <syslog.h> 70110609Stjr#include <termios.h> 7127575Scharnier#include <unistd.h> 721590Srgrimes 731590Srgrimes#define TIMEOUT 15 741590Srgrimes 75227169Sedstatic void quit(int); 76227169Sedstatic void bye(int); 77227169Sedstatic void hi(int); 7892920Simpstatic void usage(void); 791590Srgrimes 80227169Sedstatic struct timeval timeout; 81227169Sedstatic struct timeval zerotime; 82227169Sedstatic struct termios tty, ntty; 83227169Sedstatic long nexttime; /* keep the timeout time */ 84227169Sedstatic int no_timeout; /* lock terminal forever */ 85227169Sedstatic int vtyunlock; /* Unlock flag and code. */ 861590Srgrimes 871590Srgrimes/*ARGSUSED*/ 8827575Scharnierint 89102944Sdwmalonemain(int argc, char **argv) 901590Srgrimes{ 911590Srgrimes struct passwd *pw; 921590Srgrimes struct timeval timval; 9337262Sbde time_t timval_sec; 941590Srgrimes struct itimerval ntimer, otimer; 951590Srgrimes struct tm *timp; 96100806Sdd int ch, failures, sectimeout, usemine, vtylock; 97231994Skevlo char *ap, *cryptpw, *mypw, *ttynam, *tzn; 981590Srgrimes char hostname[MAXHOSTNAMELEN], s[BUFSIZ], s1[BUFSIZ]; 991590Srgrimes 10052158Snectar openlog("lock", LOG_ODELAY, LOG_AUTH); 10152158Snectar 1021590Srgrimes sectimeout = TIMEOUT; 103216696Sed pw = NULL; 1041590Srgrimes mypw = NULL; 1051590Srgrimes usemine = 0; 10699708Sdd no_timeout = 0; 107100806Sdd vtylock = 0; 108100806Sdd while ((ch = getopt(argc, argv, "npt:v")) != -1) 1091590Srgrimes switch((char)ch) { 1101590Srgrimes case 't': 11127575Scharnier if ((sectimeout = atoi(optarg)) <= 0) 11227575Scharnier errx(1, "illegal timeout value"); 1131590Srgrimes break; 1141590Srgrimes case 'p': 1151590Srgrimes usemine = 1; 11627575Scharnier if (!(pw = getpwuid(getuid()))) 11727575Scharnier errx(1, "unknown uid %d", getuid()); 1181590Srgrimes mypw = strdup(pw->pw_passwd); 1191590Srgrimes break; 12099708Sdd case 'n': 12199708Sdd no_timeout = 1; 12299708Sdd break; 123100806Sdd case 'v': 124100806Sdd vtylock = 1; 125100806Sdd break; 1261590Srgrimes case '?': 1271590Srgrimes default: 12827575Scharnier usage(); 12999708Sdd } 1301590Srgrimes timeout.tv_sec = sectimeout * 60; 1311590Srgrimes 1321590Srgrimes setuid(getuid()); /* discard privs */ 1331590Srgrimes 134110609Stjr if (tcgetattr(0, &tty)) /* get information for header */ 1351590Srgrimes exit(1); 1361590Srgrimes gethostname(hostname, sizeof(hostname)); 13727575Scharnier if (!(ttynam = ttyname(0))) 13827575Scharnier errx(1, "not a terminal?"); 139216696Sed if (strncmp(ttynam, _PATH_DEV, strlen(_PATH_DEV)) == 0) 140216696Sed ttynam += strlen(_PATH_DEV); 14127575Scharnier if (gettimeofday(&timval, (struct timezone *)NULL)) 14227575Scharnier err(1, "gettimeofday"); 1431590Srgrimes nexttime = timval.tv_sec + (sectimeout * 60); 14437262Sbde timval_sec = timval.tv_sec; 14537262Sbde timp = localtime(&timval_sec); 1461590Srgrimes ap = asctime(timp); 1471590Srgrimes tzn = timp->tm_zone; 1481590Srgrimes 1491590Srgrimes (void)signal(SIGINT, quit); 1501590Srgrimes (void)signal(SIGQUIT, quit); 151110609Stjr ntty = tty; ntty.c_lflag &= ~ECHO; 152110609Stjr (void)tcsetattr(0, TCSADRAIN|TCSASOFT, &ntty); 1531590Srgrimes 1541590Srgrimes if (!mypw) { 1551590Srgrimes /* get key and check again */ 1561590Srgrimes (void)printf("Key: "); 1571590Srgrimes if (!fgets(s, sizeof(s), stdin) || *s == '\n') 15887286Sdwmalone quit(0); 1591590Srgrimes (void)printf("\nAgain: "); 1601590Srgrimes /* 1611590Srgrimes * Don't need EOF test here, if we get EOF, then s1 != s 1621590Srgrimes * and the right things will happen. 1631590Srgrimes */ 1641590Srgrimes (void)fgets(s1, sizeof(s1), stdin); 1651590Srgrimes (void)putchar('\n'); 1661590Srgrimes if (strcmp(s1, s)) { 1671590Srgrimes (void)printf("\07lock: passwords didn't match.\n"); 168110609Stjr (void)tcsetattr(0, TCSADRAIN|TCSASOFT, &tty); 1691590Srgrimes exit(1); 1701590Srgrimes } 17127575Scharnier s[0] = '\0'; 1721590Srgrimes mypw = s1; 1731590Srgrimes } 1741590Srgrimes 1751590Srgrimes /* set signal handlers */ 1761590Srgrimes (void)signal(SIGINT, hi); 1771590Srgrimes (void)signal(SIGQUIT, hi); 1781590Srgrimes (void)signal(SIGTSTP, hi); 1791590Srgrimes (void)signal(SIGALRM, bye); 1801590Srgrimes 1811590Srgrimes ntimer.it_interval = zerotime; 1821590Srgrimes ntimer.it_value = timeout; 18399708Sdd if (!no_timeout) 18499708Sdd setitimer(ITIMER_REAL, &ntimer, &otimer); 185100806Sdd if (vtylock) { 186100806Sdd /* 187100806Sdd * If this failed, we want to err out; warn isn't good 188100806Sdd * enough, since we don't want the user to think that 189100806Sdd * everything is nice and locked because they got a 190100806Sdd * "Key:" prompt. 191100806Sdd */ 192100806Sdd if (ioctl(0, VT_LOCKSWITCH, &vtylock) == -1) { 193110609Stjr (void)tcsetattr(0, TCSADRAIN|TCSASOFT, &tty); 194100806Sdd err(1, "locking vty"); 195100806Sdd } 196100806Sdd vtyunlock = 0x2; 197100806Sdd } 1981590Srgrimes 1991590Srgrimes /* header info */ 200216696Sed if (pw != NULL) 201216737Sed (void)printf("lock: %s using %s on %s.", pw->pw_name, 202216737Sed ttynam, hostname); 203216696Sed else 204216696Sed (void)printf("lock: %s on %s.", ttynam, hostname); 205100806Sdd if (no_timeout) 206100806Sdd (void)printf(" no timeout."); 207100806Sdd else 208100806Sdd (void)printf(" timeout in %d minute%s.", sectimeout, 209100806Sdd sectimeout != 1 ? "s" : ""); 210100806Sdd if (vtylock) 211100806Sdd (void)printf(" vty locked."); 212100806Sdd (void)printf("\ntime now is %.20s%s%s", ap, tzn, ap + 19); 213100806Sdd 21499708Sdd failures = 0; 2151590Srgrimes 2161590Srgrimes for (;;) { 2171590Srgrimes (void)printf("Key: "); 2181590Srgrimes if (!fgets(s, sizeof(s), stdin)) { 2191590Srgrimes clearerr(stdin); 22087286Sdwmalone hi(0); 221124824Scperciva goto tryagain; 2221590Srgrimes } 2231590Srgrimes if (usemine) { 2241590Srgrimes s[strlen(s) - 1] = '\0'; 225231994Skevlo cryptpw = crypt(s, mypw); 226231994Skevlo if (cryptpw == NULL || !strcmp(mypw, cryptpw)) 2271590Srgrimes break; 2281590Srgrimes } 2291590Srgrimes else if (!strcmp(s, s1)) 2301590Srgrimes break; 2311590Srgrimes (void)printf("\07\n"); 23252158Snectar failures++; 23352158Snectar if (getuid() == 0) 23452158Snectar syslog(LOG_NOTICE, "%d ROOT UNLOCK FAILURE%s (%s on %s)", 23552158Snectar failures, failures > 1 ? "S": "", ttynam, hostname); 236124824Scpercivatryagain: 237124824Scperciva if (tcgetattr(0, &ntty) && (errno != EINTR)) 2381590Srgrimes exit(1); 23952158Snectar sleep(1); /* to discourage guessing */ 2401590Srgrimes } 24152158Snectar if (getuid() == 0) 24299708Sdd syslog(LOG_NOTICE, "ROOT UNLOCK ON hostname %s port %s", 24399708Sdd hostname, ttynam); 24487286Sdwmalone quit(0); 24527575Scharnier return(0); /* not reached */ 2461590Srgrimes} 2471590Srgrimes 24827575Scharnier 24927575Scharnierstatic void 250102944Sdwmaloneusage(void) 25127575Scharnier{ 252100806Sdd (void)fprintf(stderr, "usage: lock [-npv] [-t timeout]\n"); 25327575Scharnier exit(1); 25427575Scharnier} 25527575Scharnier 256227169Sedstatic void 25787286Sdwmalonehi(int signo __unused) 2581590Srgrimes{ 2591590Srgrimes struct timeval timval; 2601590Srgrimes 26199708Sdd if (!gettimeofday(&timval, (struct timezone *)NULL)) { 26299708Sdd (void)printf("lock: type in the unlock key. "); 26399708Sdd if (no_timeout) { 26499708Sdd (void)putchar('\n'); 26599708Sdd } else { 266209567Sgavin (void)printf("timeout in %jd:%jd minutes\n", 267209567Sgavin (intmax_t)(nexttime - timval.tv_sec) / 60, 268209567Sgavin (intmax_t)(nexttime - timval.tv_sec) % 60); 26999708Sdd } 27099708Sdd } 2711590Srgrimes} 2721590Srgrimes 273227169Sedstatic void 27487286Sdwmalonequit(int signo __unused) 2751590Srgrimes{ 2761590Srgrimes (void)putchar('\n'); 277110609Stjr (void)tcsetattr(0, TCSADRAIN|TCSASOFT, &tty); 278100806Sdd if (vtyunlock) 279100806Sdd (void)ioctl(0, VT_LOCKSWITCH, &vtyunlock); 2801590Srgrimes exit(0); 2811590Srgrimes} 2821590Srgrimes 283227169Sedstatic void 28487286Sdwmalonebye(int signo __unused) 2851590Srgrimes{ 28699708Sdd if (!no_timeout) { 287110609Stjr (void)tcsetattr(0, TCSADRAIN|TCSASOFT, &tty); 288100806Sdd if (vtyunlock) 289100806Sdd (void)ioctl(0, VT_LOCKSWITCH, &vtyunlock); 29099708Sdd (void)printf("lock: timeout\n"); 29199708Sdd exit(1); 29299708Sdd } 2931590Srgrimes} 294