1*f6462fb5Sschwarze /* $OpenBSD: lock.c,v 1.46 2019/07/24 20:23:09 schwarze Exp $ */
21bbed971Sderaadt /* $NetBSD: lock.c,v 1.8 1996/05/07 18:32:31 jtc Exp $ */
3df930be7Sderaadt
4df930be7Sderaadt /*
5df930be7Sderaadt * Copyright (c) 1980, 1987, 1993
6df930be7Sderaadt * The Regents of the University of California. All rights reserved.
7df930be7Sderaadt *
8df930be7Sderaadt * This code is derived from software contributed to Berkeley by
9df930be7Sderaadt * Bob Toxen.
10df930be7Sderaadt *
11df930be7Sderaadt * Redistribution and use in source and binary forms, with or without
12df930be7Sderaadt * modification, are permitted provided that the following conditions
13df930be7Sderaadt * are met:
14df930be7Sderaadt * 1. Redistributions of source code must retain the above copyright
15df930be7Sderaadt * notice, this list of conditions and the following disclaimer.
16df930be7Sderaadt * 2. Redistributions in binary form must reproduce the above copyright
17df930be7Sderaadt * notice, this list of conditions and the following disclaimer in the
18df930be7Sderaadt * documentation and/or other materials provided with the distribution.
19f75387cbSmillert * 3. Neither the name of the University nor the names of its contributors
20df930be7Sderaadt * may be used to endorse or promote products derived from this software
21df930be7Sderaadt * without specific prior written permission.
22df930be7Sderaadt *
23df930be7Sderaadt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24df930be7Sderaadt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25df930be7Sderaadt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26df930be7Sderaadt * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27df930be7Sderaadt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28df930be7Sderaadt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29df930be7Sderaadt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30df930be7Sderaadt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31df930be7Sderaadt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32df930be7Sderaadt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33df930be7Sderaadt * SUCH DAMAGE.
34df930be7Sderaadt */
35df930be7Sderaadt
36df930be7Sderaadt /*
371e4c0f81Sjca * Lock a terminal up until the given key or user password is entered,
381e4c0f81Sjca * or the given interval times out.
39df930be7Sderaadt */
40df930be7Sderaadt
41df930be7Sderaadt #include <sys/stat.h>
42df930be7Sderaadt #include <sys/time.h>
43df930be7Sderaadt #include <signal.h>
44df930be7Sderaadt
45df930be7Sderaadt #include <ctype.h>
46df930be7Sderaadt #include <err.h>
47df930be7Sderaadt #include <pwd.h>
48ed8b5f35Smillert #include <readpassphrase.h>
49df930be7Sderaadt #include <stdio.h>
501bbed971Sderaadt #include <stdlib.h>
51df930be7Sderaadt #include <string.h>
52df930be7Sderaadt #include <termios.h>
531bbed971Sderaadt #include <unistd.h>
54b9fc9a72Sderaadt #include <limits.h>
55df930be7Sderaadt
56ed8b5f35Smillert #include <login_cap.h>
57ed8b5f35Smillert #include <bsd_auth.h>
584e0e1dc4Smillert
59c72b5b24Smillert void bye(int);
60c72b5b24Smillert void hi(int);
618a6602a7Scheloha void usage(void);
62df930be7Sderaadt
63*f6462fb5Sschwarze int no_timeout = 0; /* lock terminal forever */
64df930be7Sderaadt
65266ade72Smillert int
main(int argc,char * argv[])66d0c2d48dSderaadt main(int argc, char *argv[])
67df930be7Sderaadt {
68b9fc9a72Sderaadt char hostname[HOST_NAME_MAX+1], s[BUFSIZ], s1[BUFSIZ], date[256];
69757e8834Stedu char hash[_PASSWORD_LEN];
70d0c2d48dSderaadt char *p, *style, *nstyle, *ttynam;
71df930be7Sderaadt struct itimerval ntimer, otimer;
72b02d8f05Stedu struct timeval timeout;
73c52c9307Smartynas int ch, sectimeout, usemine, cnt, tries = 10, backoff = 3;
74769f22eaSderaadt const char *errstr;
75d0c2d48dSderaadt struct passwd *pw;
76df930be7Sderaadt struct tm *timp;
77df930be7Sderaadt time_t curtime;
78ed8b5f35Smillert login_cap_t *lc;
79df930be7Sderaadt
80*f6462fb5Sschwarze sectimeout = 0;
81ed8b5f35Smillert style = NULL;
82df930be7Sderaadt usemine = 0;
83b02d8f05Stedu memset(&timeout, 0, sizeof(timeout));
84df930be7Sderaadt
8591211a55Stedu if (pledge("stdio rpath wpath getpw tty proc exec", NULL) == -1)
860bd1216cSderaadt err(1, "pledge");
87060ad421Sderaadt
88df930be7Sderaadt if (!(pw = getpwuid(getuid())))
89b0ca7b2aSderaadt errx(1, "unknown uid %u.", getuid());
90df930be7Sderaadt
91ed8b5f35Smillert lc = login_getclass(pw->pw_class);
92c52c9307Smartynas if (lc != NULL) {
93c52c9307Smartynas /*
94c52c9307Smartynas * We allow "login-tries" attempts to login but start
95c52c9307Smartynas * slowing down after "login-backoff" attempts.
96c52c9307Smartynas */
97a8b197cdStedu tries = login_getcapnum(lc, "login-tries", 10, 10);
98a8b197cdStedu backoff = login_getcapnum(lc, "login-backoff", 3, 3);
99c52c9307Smartynas }
100ed8b5f35Smillert
1010654e9b7Sjca while ((ch = getopt(argc, argv, "a:npt:")) != -1) {
102ed8b5f35Smillert switch (ch) {
103ed8b5f35Smillert case 'a':
104ed8b5f35Smillert if (lc) {
105ed8b5f35Smillert style = login_getstyle(lc, optarg, "auth-lock");
106ed8b5f35Smillert if (style == NULL)
107ed8b5f35Smillert errx(1,
108ed8b5f35Smillert "invalid authentication style: %s",
109ed8b5f35Smillert optarg);
110ed8b5f35Smillert }
111ed8b5f35Smillert usemine = 1;
112ed8b5f35Smillert break;
113df930be7Sderaadt case 't':
114a8b197cdStedu sectimeout = strtonum(optarg, 1, INT_MAX, &errstr);
115769f22eaSderaadt if (errstr)
116769f22eaSderaadt errx(1, "timeout %s: %s", errstr, optarg);
117df930be7Sderaadt break;
118df930be7Sderaadt case 'p':
119df930be7Sderaadt usemine = 1;
120df930be7Sderaadt break;
1210654e9b7Sjca case 'n':
122*f6462fb5Sschwarze no_timeout = 1;
1230654e9b7Sjca break;
124df930be7Sderaadt default:
1258a6602a7Scheloha usage();
126df930be7Sderaadt }
1276bc13b30Stedu }
128*f6462fb5Sschwarze if (sectimeout == 0)
129*f6462fb5Sschwarze no_timeout = 1;
130df930be7Sderaadt
131df930be7Sderaadt gethostname(hostname, sizeof(hostname));
13283536322Stobias if (usemine && lc == NULL)
13383536322Stobias errx(1, "login class not found");
134ed8b5f35Smillert if (!(ttynam = ttyname(STDIN_FILENO)))
135df930be7Sderaadt errx(1, "not a terminal?");
136ed8b5f35Smillert curtime = time(NULL);
137df930be7Sderaadt timp = localtime(&curtime);
138ed8b5f35Smillert strftime(date, sizeof(date), "%c", timp);
139df930be7Sderaadt
140ed8b5f35Smillert if (!usemine) {
141df930be7Sderaadt /* get key and check again */
142ed8b5f35Smillert if (!readpassphrase("Key: ", s, sizeof(s), RPP_ECHO_OFF) ||
143ed8b5f35Smillert *s == '\0')
144ed8b5f35Smillert exit(0);
145df930be7Sderaadt /*
146df930be7Sderaadt * Don't need EOF test here, if we get EOF, then s1 != s
147df930be7Sderaadt * and the right things will happen.
148df930be7Sderaadt */
149a8b197cdStedu readpassphrase("Again: ", s1, sizeof(s1), RPP_ECHO_OFF);
150df930be7Sderaadt if (strcmp(s1, s)) {
151ed8b5f35Smillert warnx("\apasswords didn't match.");
152df930be7Sderaadt exit(1);
153df930be7Sderaadt }
154757e8834Stedu crypt_newhash(s, "bcrypt", hash, sizeof(hash));
1553a7efd93Smestre explicit_bzero(s, sizeof(s));
156757e8834Stedu explicit_bzero(s1, sizeof(s1));
157df930be7Sderaadt }
158df930be7Sderaadt
159df930be7Sderaadt /* set signal handlers */
160a8b197cdStedu signal(SIGINT, hi);
161a8b197cdStedu signal(SIGQUIT, hi);
162a8b197cdStedu signal(SIGTSTP, hi);
163a8b197cdStedu signal(SIGALRM, bye);
164df930be7Sderaadt
1652d9f0fe4Scheloha if (!no_timeout) {
1662d9f0fe4Scheloha timeout.tv_sec = (time_t)sectimeout * 60;
167b02d8f05Stedu memset(&ntimer, 0, sizeof(ntimer));
168df930be7Sderaadt ntimer.it_value = timeout;
169df930be7Sderaadt setitimer(ITIMER_REAL, &ntimer, &otimer);
1702d9f0fe4Scheloha }
171df930be7Sderaadt
172df930be7Sderaadt /* header info */
173dde5a603Sdownsj if (no_timeout) {
174a8b197cdStedu fprintf(stderr,
175ed8b5f35Smillert "%s: %s on %s. no timeout\ntime now is %s\n",
1764b9dbb2eStedu getprogname(), ttynam, hostname, date);
177dde5a603Sdownsj } else {
178a8b197cdStedu fprintf(stderr,
179ed8b5f35Smillert "%s: %s on %s. timeout in %d minutes\ntime now is %s\n",
1804b9dbb2eStedu getprogname(), ttynam, hostname, sectimeout, date);
181dde5a603Sdownsj }
182df930be7Sderaadt
183c52c9307Smartynas for (cnt = 0;;) {
184c24b2f3dStedu if (!readpassphrase("Key: ", s, sizeof(s), RPP_ECHO_OFF))
185c24b2f3dStedu continue;
186c24b2f3dStedu if (strlen(s) == 0) {
187266ade72Smillert hi(0);
188df930be7Sderaadt continue;
189df930be7Sderaadt }
190df930be7Sderaadt if (usemine) {
191df930be7Sderaadt /*
192ed8b5f35Smillert * If user entered 's/key' or the style specified via
193ed8b5f35Smillert * the '-a' argument, auth_userokay() will prompt
194ed8b5f35Smillert * for a new password. Otherwise, use what we have.
195df930be7Sderaadt */
196ed8b5f35Smillert if ((strcmp(s, "s/key") == 0 &&
197ed8b5f35Smillert (nstyle = login_getstyle(lc, "skey", "auth-lock")))
198ed8b5f35Smillert || ((nstyle = style) && strcmp(s, nstyle) == 0))
199ed8b5f35Smillert p = NULL;
200ed8b5f35Smillert else
201ed8b5f35Smillert p = s;
2023a7efd93Smestre if (auth_userokay(pw->pw_name, nstyle, "auth-lock",
2033a7efd93Smestre p)) {
2043a7efd93Smestre explicit_bzero(s, sizeof(s));
205ed8b5f35Smillert break;
2063a7efd93Smestre }
207757e8834Stedu } else if (crypt_checkpass(s, hash) == 0) {
2083a7efd93Smestre explicit_bzero(s, sizeof(s));
2092e4bb4d9Stb explicit_bzero(hash, sizeof(hash));
210ed8b5f35Smillert break;
2113a7efd93Smestre }
212a8b197cdStedu putc('\a', stderr);
213c52c9307Smartynas cnt %= tries;
214c52c9307Smartynas if (++cnt > backoff) {
215c52c9307Smartynas sigset_t set, oset;
216c52c9307Smartynas sigfillset(&set);
217c52c9307Smartynas sigprocmask(SIG_BLOCK, &set, &oset);
218c52c9307Smartynas sleep((u_int)((cnt - backoff) * tries / 2));
219c52c9307Smartynas sigprocmask(SIG_SETMASK, &oset, NULL);
220c52c9307Smartynas }
221ed8b5f35Smillert }
222df930be7Sderaadt
223ed8b5f35Smillert exit(0);
224df930be7Sderaadt }
225df930be7Sderaadt
226df930be7Sderaadt void
hi(int signo)227318c2520Sderaadt hi(int signo)
228df930be7Sderaadt {
229c9c0bf19Stedu struct itimerval left;
230df930be7Sderaadt
231a8b197cdStedu dprintf(STDERR_FILENO, "%s: type in the unlock key.",
2324b9dbb2eStedu getprogname());
233c9c0bf19Stedu if (!no_timeout) {
234a8b197cdStedu getitimer(ITIMER_REAL, &left);
235a8b197cdStedu dprintf(STDERR_FILENO, " timeout in %lld:%02d minutes",
236c9c0bf19Stedu (long long)(left.it_value.tv_sec / 60),
237c9c0bf19Stedu (int)(left.it_value.tv_sec % 60));
238dde5a603Sdownsj }
239a8b197cdStedu dprintf(STDERR_FILENO, "\n");
240df930be7Sderaadt }
241df930be7Sderaadt
242df930be7Sderaadt void
bye(int signo)243318c2520Sderaadt bye(int signo)
244df930be7Sderaadt {
245ed8b5f35Smillert
246ed8b5f35Smillert if (!no_timeout)
24782aaa63dSmillert warnx("timeout");
24882aaa63dSmillert _exit(1);
249dde5a603Sdownsj }
2508a6602a7Scheloha
2518a6602a7Scheloha void
usage(void)2528a6602a7Scheloha usage(void)
2538a6602a7Scheloha {
254*f6462fb5Sschwarze fprintf(stderr, "usage: %s [-np] [-a style] [-t timeout]\n",
2558a6602a7Scheloha getprogname());
2568a6602a7Scheloha exit(1);
2578a6602a7Scheloha }
258