lock.c revision 239991
1132718Skan/*
2169689Skan * Copyright (c) 1980, 1987, 1993
3132718Skan *	The Regents of the University of California.  All rights reserved.
4132718Skan *
5132718Skan * This code is derived from software contributed to Berkeley by
6132718Skan * Bob Toxen.
7132718Skan *
8132718Skan * Redistribution and use in source and binary forms, with or without
9132718Skan * modification, are permitted provided that the following conditions
10132718Skan * are met:
11132718Skan * 1. Redistributions of source code must retain the above copyright
12132718Skan *    notice, this list of conditions and the following disclaimer.
13132718Skan * 2. Redistributions in binary form must reproduce the above copyright
14132718Skan *    notice, this list of conditions and the following disclaimer in the
15132718Skan *    documentation and/or other materials provided with the distribution.
16132718Skan * 4. Neither the name of the University nor the names of its contributors
17132718Skan *    may be used to endorse or promote products derived from this software
18132718Skan *    without specific prior written permission.
19169689Skan *
20169689Skan * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21132718Skan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22132718Skan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23132718Skan * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24169689Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25169689Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26132718Skan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27169689Skan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28169689Skan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29169689Skan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30169689Skan * SUCH DAMAGE.
31169689Skan */
32169689Skan
33169689Skan#ifndef lint
34169689Skanstatic const char copyright[] =
35169689Skan"@(#) Copyright (c) 1980, 1987, 1993\n\
36169689Skan	The Regents of the University of California.  All rights reserved.\n";
37169689Skan#endif /* not lint */
38169689Skan
39169689Skan#ifndef lint
40169689Skan#if 0
41169689Skanstatic char sccsid[] = "@(#)lock.c	8.1 (Berkeley) 6/6/93";
42169689Skan#endif
43169689Skan#endif /* not lint */
44169689Skan#include <sys/cdefs.h>
45169689Skan__FBSDID("$FreeBSD: head/usr.bin/lock/lock.c 239991 2012-09-01 14:45:15Z ed $");
46169689Skan
47169689Skan/*
48169689Skan * Lock a terminal up until the given key is entered or the given
49132718Skan * interval times out.
50132718Skan *
51132718Skan * Timeout interval is by default TIMEOUT, it can be changed with
52132718Skan * an argument of the form -time where time is in minutes
53132718Skan */
54132718Skan
55132718Skan#include <sys/param.h>
56132718Skan#include <sys/stat.h>
57132718Skan#include <sys/signal.h>
58169689Skan#include <sys/consio.h>
59169689Skan
60169689Skan#include <err.h>
61169689Skan#include <ctype.h>
62169689Skan#include <errno.h>
63169689Skan#include <paths.h>
64132718Skan#include <pwd.h>
65169689Skan#include <stdint.h>
66132718Skan#include <stdio.h>
67132718Skan#include <stdlib.h>
68169689Skan#include <string.h>
69169689Skan#include <syslog.h>
70169689Skan#include <termios.h>
71169689Skan#include <time.h>
72169689Skan#include <unistd.h>
73132718Skan
74132718Skan#define	TIMEOUT	15
75169689Skan
76169689Skanstatic void quit(int);
77169689Skanstatic void bye(int);
78169689Skanstatic void hi(int);
79169689Skanstatic void usage(void);
80169689Skan
81169689Skanstatic struct timeval	timeout;
82169689Skanstatic struct timeval	zerotime;
83169689Skanstatic struct termios	tty, ntty;
84132718Skanstatic long		nexttime;		/* keep the timeout time */
85132718Skanstatic int		no_timeout;		/* lock terminal forever */
86132718Skanstatic int		vtyunlock;		/* Unlock flag and code. */
87132718Skan
88132718Skan/*ARGSUSED*/
89132718Skanint
90132718Skanmain(int argc, char **argv)
91169689Skan{
92169689Skan	struct passwd *pw;
93169689Skan	struct itimerval ntimer, otimer;
94132718Skan	struct tm *timp;
95132718Skan	time_t timval;
96132718Skan	int ch, failures, sectimeout, usemine, vtylock;
97169689Skan	char *ap, *cryptpw, *mypw, *ttynam, *tzn;
98169689Skan	char hostname[MAXHOSTNAMELEN], s[BUFSIZ], s1[BUFSIZ];
99132718Skan
100169689Skan	openlog("lock", LOG_ODELAY, LOG_AUTH);
101132718Skan
102132718Skan	sectimeout = TIMEOUT;
103132718Skan	pw = NULL;
104132718Skan	mypw = NULL;
105132718Skan	usemine = 0;
106132718Skan	no_timeout = 0;
107132718Skan	vtylock = 0;
108132718Skan	while ((ch = getopt(argc, argv, "npt:v")) != -1)
109132718Skan		switch((char)ch) {
110132718Skan		case 't':
111132718Skan			if ((sectimeout = atoi(optarg)) <= 0)
112132718Skan				errx(1, "illegal timeout value");
113132718Skan			break;
114132718Skan		case 'p':
115132718Skan			usemine = 1;
116132718Skan			if (!(pw = getpwuid(getuid())))
117132718Skan				errx(1, "unknown uid %d", getuid());
118132718Skan			mypw = strdup(pw->pw_passwd);
119132718Skan			break;
120132718Skan		case 'n':
121132718Skan			no_timeout = 1;
122132718Skan			break;
123132718Skan		case 'v':
124132718Skan			vtylock = 1;
125132718Skan			break;
126132718Skan		case '?':
127132718Skan		default:
128132718Skan			usage();
129132718Skan		}
130169689Skan	timeout.tv_sec = sectimeout * 60;
131169689Skan
132169689Skan	setuid(getuid());		/* discard privs */
133169689Skan
134169689Skan	if (tcgetattr(0, &tty))		/* get information for header */
135169689Skan		exit(1);
136169689Skan	gethostname(hostname, sizeof(hostname));
137169689Skan	if (!(ttynam = ttyname(0)))
138169689Skan		errx(1, "not a terminal?");
139132718Skan	if (strncmp(ttynam, _PATH_DEV, strlen(_PATH_DEV)) == 0)
140169689Skan		ttynam += strlen(_PATH_DEV);
141169689Skan	timval = time(NULL);
142132718Skan	nexttime = timval + (sectimeout * 60);
143132718Skan	timp = localtime(&timval);
144132718Skan	ap = asctime(timp);
145169689Skan	tzn = timp->tm_zone;
146169689Skan
147169689Skan	(void)signal(SIGINT, quit);
148132718Skan	(void)signal(SIGQUIT, quit);
149132718Skan	ntty = tty; ntty.c_lflag &= ~ECHO;
150169689Skan	(void)tcsetattr(0, TCSADRAIN|TCSASOFT, &ntty);
151169689Skan
152169689Skan	if (!mypw) {
153132718Skan		/* get key and check again */
154169689Skan		(void)printf("Key: ");
155169689Skan		if (!fgets(s, sizeof(s), stdin) || *s == '\n')
156132718Skan			quit(0);
157132718Skan		(void)printf("\nAgain: ");
158169689Skan		/*
159169689Skan		 * Don't need EOF test here, if we get EOF, then s1 != s
160169689Skan		 * and the right things will happen.
161132718Skan		 */
162132718Skan		(void)fgets(s1, sizeof(s1), stdin);
163169689Skan		(void)putchar('\n');
164132718Skan		if (strcmp(s1, s)) {
165169689Skan			(void)printf("\07lock: passwords didn't match.\n");
166169689Skan			(void)tcsetattr(0, TCSADRAIN|TCSASOFT, &tty);
167169689Skan			exit(1);
168169689Skan		}
169169689Skan		s[0] = '\0';
170169689Skan		mypw = s1;
171169689Skan	}
172169689Skan
173132718Skan	/* set signal handlers */
174132718Skan	(void)signal(SIGINT, hi);
175169689Skan	(void)signal(SIGQUIT, hi);
176132718Skan	(void)signal(SIGTSTP, hi);
177132718Skan	(void)signal(SIGALRM, bye);
178132718Skan
179169689Skan	ntimer.it_interval = zerotime;
180132718Skan	ntimer.it_value = timeout;
181169689Skan	if (!no_timeout)
182132718Skan		setitimer(ITIMER_REAL, &ntimer, &otimer);
183169689Skan	if (vtylock) {
184169689Skan		/*
185132718Skan		 * If this failed, we want to err out; warn isn't good
186132718Skan		 * enough, since we don't want the user to think that
187132718Skan		 * everything is nice and locked because they got a
188169689Skan		 * "Key:" prompt.
189169689Skan		 */
190169689Skan		if (ioctl(0, VT_LOCKSWITCH, &vtylock) == -1) {
191169689Skan			(void)tcsetattr(0, TCSADRAIN|TCSASOFT, &tty);
192132718Skan			err(1, "locking vty");
193132718Skan		}
194169689Skan		vtyunlock = 0x2;
195169689Skan	}
196169689Skan
197169689Skan	/* header info */
198169689Skan	if (pw != NULL)
199132718Skan		(void)printf("lock: %s using %s on %s.", pw->pw_name,
200132718Skan		    ttynam, hostname);
201132718Skan	else
202132718Skan		(void)printf("lock: %s on %s.", ttynam, hostname);
203132718Skan	if (no_timeout)
204132718Skan		(void)printf(" no timeout.");
205169689Skan	else
206169689Skan		(void)printf(" timeout in %d minute%s.", sectimeout,
207132718Skan		    sectimeout != 1 ? "s" : "");
208132718Skan	if (vtylock)
209169689Skan		(void)printf(" vty locked.");
210169689Skan	(void)printf("\ntime now is %.20s%s%s", ap, tzn, ap + 19);
211132718Skan
212132718Skan	failures = 0;
213169689Skan
214169689Skan	for (;;) {
215169689Skan		(void)printf("Key: ");
216169689Skan		if (!fgets(s, sizeof(s), stdin)) {
217169689Skan			clearerr(stdin);
218169689Skan			hi(0);
219169689Skan			goto tryagain;
220169689Skan		}
221132718Skan		if (usemine) {
222169689Skan			s[strlen(s) - 1] = '\0';
223169689Skan			cryptpw = crypt(s, mypw);
224169689Skan			if (cryptpw == NULL || !strcmp(mypw, cryptpw))
225169689Skan				break;
226169689Skan		}
227169689Skan		else if (!strcmp(s, s1))
228169689Skan			break;
229132718Skan		(void)printf("\07\n");
230132718Skan	    	failures++;
231169689Skan		if (getuid() == 0)
232169689Skan	    	    syslog(LOG_NOTICE, "%d ROOT UNLOCK FAILURE%s (%s on %s)",
233169689Skan			failures, failures > 1 ? "S": "", ttynam, hostname);
234169689Skantryagain:
235169689Skan		if (tcgetattr(0, &ntty) && (errno != EINTR))
236169689Skan			exit(1);
237169689Skan		sleep(1);		/* to discourage guessing */
238169689Skan	}
239169689Skan	if (getuid() == 0)
240169689Skan		syslog(LOG_NOTICE, "ROOT UNLOCK ON hostname %s port %s",
241169689Skan		    hostname, ttynam);
242169689Skan	quit(0);
243132718Skan	return(0); /* not reached */
244132718Skan}
245132718Skan
246132718Skan
247169689Skanstatic void
248132718Skanusage(void)
249169689Skan{
250132718Skan	(void)fprintf(stderr, "usage: lock [-npv] [-t timeout]\n");
251169689Skan	exit(1);
252169689Skan}
253132718Skan
254169689Skanstatic void
255169689Skanhi(int signo __unused)
256169689Skan{
257132718Skan	time_t timval;
258132718Skan
259132718Skan	timval = time(NULL);
260169689Skan	(void)printf("lock: type in the unlock key. ");
261169689Skan	if (no_timeout) {
262169689Skan		(void)putchar('\n');
263169689Skan	} else {
264169689Skan		(void)printf("timeout in %jd:%jd minutes\n",
265132718Skan		    (intmax_t)(nexttime - timval) / 60,
266169689Skan		    (intmax_t)(nexttime - timval) % 60);
267169689Skan	}
268169689Skan}
269169689Skan
270169689Skanstatic void
271169689Skanquit(int signo __unused)
272169689Skan{
273169689Skan	(void)putchar('\n');
274132718Skan	(void)tcsetattr(0, TCSADRAIN|TCSASOFT, &tty);
275132718Skan	if (vtyunlock)
276132718Skan		(void)ioctl(0, VT_LOCKSWITCH, &vtyunlock);
277132718Skan	exit(0);
278169689Skan}
279169689Skan
280169689Skanstatic void
281169689Skanbye(int signo __unused)
282169689Skan{
283132718Skan	if (!no_timeout) {
284169689Skan		(void)tcsetattr(0, TCSADRAIN|TCSASOFT, &tty);
285169689Skan		if (vtyunlock)
286132718Skan			(void)ioctl(0, VT_LOCKSWITCH, &vtyunlock);
287132718Skan		(void)printf("lock: timeout\n");
288169689Skan		exit(1);
289132718Skan	}
290169689Skan}
291169689Skan