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