GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/lock/lock.c Lines: 0 103 0.0 %
Date: 2017-11-13 Branches: 0 61 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: lock.c,v 1.41 2017/09/06 21:02:31 tb Exp $	*/
2
/*	$NetBSD: lock.c,v 1.8 1996/05/07 18:32:31 jtc Exp $	*/
3
4
/*
5
 * Copyright (c) 1980, 1987, 1993
6
 *	The Regents of the University of California.  All rights reserved.
7
 *
8
 * This code is derived from software contributed to Berkeley by
9
 * Bob Toxen.
10
 *
11
 * Redistribution and use in source and binary forms, with or without
12
 * modification, are permitted provided that the following conditions
13
 * are met:
14
 * 1. Redistributions of source code must retain the above copyright
15
 *    notice, this list of conditions and the following disclaimer.
16
 * 2. Redistributions in binary form must reproduce the above copyright
17
 *    notice, this list of conditions and the following disclaimer in the
18
 *    documentation and/or other materials provided with the distribution.
19
 * 3. Neither the name of the University nor the names of its contributors
20
 *    may be used to endorse or promote products derived from this software
21
 *    without specific prior written permission.
22
 *
23
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33
 * SUCH DAMAGE.
34
 */
35
36
/*
37
 * Lock a terminal up until the given key is entered, until the root
38
 * password is entered, or the given interval times out.
39
 *
40
 * Timeout interval is by default TIMEOUT, it can be changed with
41
 * an argument of the form -time where time is in minutes
42
 */
43
44
#include <sys/stat.h>
45
#include <sys/time.h>
46
#include <signal.h>
47
48
#include <ctype.h>
49
#include <err.h>
50
#include <pwd.h>
51
#include <readpassphrase.h>
52
#include <stdio.h>
53
#include <stdlib.h>
54
#include <string.h>
55
#include <termios.h>
56
#include <unistd.h>
57
#include <limits.h>
58
59
#include <login_cap.h>
60
#include <bsd_auth.h>
61
62
#define	TIMEOUT	15
63
64
void bye(int);
65
void hi(int);
66
67
int	no_timeout;			/* lock terminal forever */
68
69
int
70
main(int argc, char *argv[])
71
{
72
	char hostname[HOST_NAME_MAX+1], s[BUFSIZ], s1[BUFSIZ], date[256];
73
	char hash[_PASSWORD_LEN];
74
	char *p, *style, *nstyle, *ttynam;
75
	struct itimerval ntimer, otimer;
76
	struct timeval timeout;
77
	int ch, sectimeout, usemine, cnt, tries = 10, backoff = 3;
78
	const char *errstr;
79
	struct passwd *pw;
80
	struct tm *timp;
81
	time_t curtime;
82
	login_cap_t *lc;
83
84
	sectimeout = TIMEOUT;
85
	style = NULL;
86
	usemine = 0;
87
	no_timeout = 0;
88
	memset(&timeout, 0, sizeof(timeout));
89
90
	if (pledge("stdio rpath wpath getpw tty proc exec flock cpath", NULL) == -1)
91
		err(1, "pledge");
92
93
	if (!(pw = getpwuid(getuid())))
94
		errx(1, "unknown uid %u.", getuid());
95
96
	lc = login_getclass(pw->pw_class);
97
	if (lc != NULL) {
98
		/*
99
		 * We allow "login-tries" attempts to login but start
100
		 * slowing down after "login-backoff" attempts.
101
		 */
102
		tries = login_getcapnum(lc, "login-tries", 10, 10);
103
		backoff = login_getcapnum(lc, "login-backoff", 3, 3);
104
	}
105
106
	while ((ch = getopt(argc, argv, "a:npt:")) != -1) {
107
		switch (ch) {
108
		case 'a':
109
			if (lc) {
110
				style = login_getstyle(lc, optarg, "auth-lock");
111
				if (style == NULL)
112
					errx(1,
113
					    "invalid authentication style: %s",
114
					    optarg);
115
			}
116
			usemine = 1;
117
			break;
118
		case 't':
119
			sectimeout = strtonum(optarg, 1, INT_MAX, &errstr);
120
			if (errstr)
121
				errx(1, "timeout %s: %s", errstr, optarg);
122
			break;
123
		case 'p':
124
			usemine = 1;
125
			break;
126
		case 'n':
127
			no_timeout = 1;
128
			break;
129
		default:
130
			fprintf(stderr,
131
			    "usage: %s [-np] [-a style] [-t timeout]\n",
132
			    getprogname());
133
			exit(1);
134
		}
135
	}
136
	timeout.tv_sec = sectimeout * 60;
137
138
	gethostname(hostname, sizeof(hostname));
139
	if (usemine && lc == NULL)
140
		errx(1, "login class not found");
141
	if (!(ttynam = ttyname(STDIN_FILENO)))
142
		errx(1, "not a terminal?");
143
	curtime = time(NULL);
144
	timp = localtime(&curtime);
145
	strftime(date, sizeof(date), "%c", timp);
146
147
	if (!usemine) {
148
		/* get key and check again */
149
		if (!readpassphrase("Key: ", s, sizeof(s), RPP_ECHO_OFF) ||
150
		    *s == '\0')
151
			exit(0);
152
		/*
153
		 * Don't need EOF test here, if we get EOF, then s1 != s
154
		 * and the right things will happen.
155
		 */
156
		readpassphrase("Again: ", s1, sizeof(s1), RPP_ECHO_OFF);
157
		if (strcmp(s1, s)) {
158
			warnx("\apasswords didn't match.");
159
			exit(1);
160
		}
161
		crypt_newhash(s, "bcrypt", hash, sizeof(hash));
162
		explicit_bzero(s, sizeof(s));
163
		explicit_bzero(s1, sizeof(s1));
164
	}
165
166
	/* set signal handlers */
167
	signal(SIGINT, hi);
168
	signal(SIGQUIT, hi);
169
	signal(SIGTSTP, hi);
170
	signal(SIGALRM, bye);
171
172
	memset(&ntimer, 0, sizeof(ntimer));
173
	ntimer.it_value = timeout;
174
	if (!no_timeout)
175
		setitimer(ITIMER_REAL, &ntimer, &otimer);
176
177
	/* header info */
178
	if (no_timeout) {
179
		fprintf(stderr,
180
		    "%s: %s on %s. no timeout\ntime now is %s\n",
181
		    getprogname(), ttynam, hostname, date);
182
	} else {
183
		fprintf(stderr,
184
		    "%s: %s on %s. timeout in %d minutes\ntime now is %s\n",
185
		    getprogname(), ttynam, hostname, sectimeout, date);
186
	}
187
188
	for (cnt = 0;;) {
189
		if (!readpassphrase("Key: ", s, sizeof(s), RPP_ECHO_OFF))
190
			continue;
191
		if (strlen(s) == 0) {
192
			hi(0);
193
			continue;
194
		}
195
		if (usemine) {
196
			/*
197
			 * If user entered 's/key' or the style specified via
198
			 * the '-a' argument, auth_userokay() will prompt
199
			 * for a new password.  Otherwise, use what we have.
200
			 */
201
			if ((strcmp(s, "s/key") == 0 &&
202
			    (nstyle = login_getstyle(lc, "skey", "auth-lock")))
203
			    || ((nstyle = style) && strcmp(s, nstyle) == 0))
204
				p = NULL;
205
			else
206
				p = s;
207
			if (auth_userokay(pw->pw_name, nstyle, "auth-lock",
208
			    p)) {
209
				explicit_bzero(s, sizeof(s));
210
				break;
211
			}
212
		} else if (crypt_checkpass(s, hash) == 0) {
213
			explicit_bzero(s, sizeof(s));
214
			explicit_bzero(hash, sizeof(hash));
215
			break;
216
		}
217
		putc('\a', stderr);
218
		cnt %= tries;
219
		if (++cnt > backoff) {
220
			sigset_t set, oset;
221
			sigfillset(&set);
222
			sigprocmask(SIG_BLOCK, &set, &oset);
223
			sleep((u_int)((cnt - backoff) * tries / 2));
224
			sigprocmask(SIG_SETMASK, &oset, NULL);
225
		}
226
	}
227
228
	exit(0);
229
}
230
231
void
232
hi(int signo)
233
{
234
	struct itimerval left;
235
236
	dprintf(STDERR_FILENO, "%s: type in the unlock key.",
237
	    getprogname());
238
	if (!no_timeout) {
239
		getitimer(ITIMER_REAL, &left);
240
		dprintf(STDERR_FILENO, " timeout in %lld:%02d minutes",
241
		    (long long)(left.it_value.tv_sec / 60),
242
		    (int)(left.it_value.tv_sec % 60));
243
	}
244
	dprintf(STDERR_FILENO, "\n");
245
}
246
247
void
248
bye(int signo)
249
{
250
251
	if (!no_timeout)
252
		warnx("timeout");
253
	_exit(1);
254
}