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: releng/10.3/usr.bin/lock/lock.c 241848 2012-10-22 03:07:05Z eadler $"); 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/signal.h> 58100806Sdd#include <sys/consio.h> 59239991Sed 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> 71239991Sed#include <time.h> 7227575Scharnier#include <unistd.h> 731590Srgrimes 741590Srgrimes#define TIMEOUT 15 751590Srgrimes 76227169Sedstatic void quit(int); 77227169Sedstatic void bye(int); 78227169Sedstatic void hi(int); 7992920Simpstatic void usage(void); 801590Srgrimes 81227169Sedstatic struct timeval timeout; 82227169Sedstatic struct timeval zerotime; 83227169Sedstatic struct termios tty, ntty; 84227169Sedstatic long nexttime; /* keep the timeout time */ 85227169Sedstatic int no_timeout; /* lock terminal forever */ 86227169Sedstatic int vtyunlock; /* Unlock flag and code. */ 871590Srgrimes 881590Srgrimes/*ARGSUSED*/ 8927575Scharnierint 90102944Sdwmalonemain(int argc, char **argv) 911590Srgrimes{ 921590Srgrimes struct passwd *pw; 931590Srgrimes struct itimerval ntimer, otimer; 941590Srgrimes struct tm *timp; 95239991Sed time_t timval; 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 132241848Seadler /* discard privs */ 133241848Seadler if (setuid(getuid()) != 0) 134241848Seadler errx(1, "setuid failed"); 1351590Srgrimes 136110609Stjr if (tcgetattr(0, &tty)) /* get information for header */ 1371590Srgrimes exit(1); 1381590Srgrimes gethostname(hostname, sizeof(hostname)); 13927575Scharnier if (!(ttynam = ttyname(0))) 14027575Scharnier errx(1, "not a terminal?"); 141216696Sed if (strncmp(ttynam, _PATH_DEV, strlen(_PATH_DEV)) == 0) 142216696Sed ttynam += strlen(_PATH_DEV); 143239991Sed timval = time(NULL); 144239991Sed nexttime = timval + (sectimeout * 60); 145239991Sed timp = localtime(&timval); 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{ 259239991Sed time_t timval; 2601590Srgrimes 261239991Sed timval = time(NULL); 262239991Sed (void)printf("lock: type in the unlock key. "); 263239991Sed if (no_timeout) { 264239991Sed (void)putchar('\n'); 265239991Sed } else { 266239991Sed (void)printf("timeout in %jd:%jd minutes\n", 267239991Sed (intmax_t)(nexttime - timval) / 60, 268239991Sed (intmax_t)(nexttime - timval) % 60); 26999708Sdd } 2701590Srgrimes} 2711590Srgrimes 272227169Sedstatic void 27387286Sdwmalonequit(int signo __unused) 2741590Srgrimes{ 2751590Srgrimes (void)putchar('\n'); 276110609Stjr (void)tcsetattr(0, TCSADRAIN|TCSASOFT, &tty); 277100806Sdd if (vtyunlock) 278100806Sdd (void)ioctl(0, VT_LOCKSWITCH, &vtyunlock); 2791590Srgrimes exit(0); 2801590Srgrimes} 2811590Srgrimes 282227169Sedstatic void 28387286Sdwmalonebye(int signo __unused) 2841590Srgrimes{ 28599708Sdd if (!no_timeout) { 286110609Stjr (void)tcsetattr(0, TCSADRAIN|TCSASOFT, &tty); 287100806Sdd if (vtyunlock) 288100806Sdd (void)ioctl(0, VT_LOCKSWITCH, &vtyunlock); 28999708Sdd (void)printf("lock: timeout\n"); 29099708Sdd exit(1); 29199708Sdd } 2921590Srgrimes} 293