xref: /minix3/usr.bin/lock/lock.c (revision 84d9c625bfea59e274550651111ae9edfdc40fbd)
1*84d9c625SLionel Sambuc /*	$NetBSD: lock.c,v 1.33 2013/10/18 20:47:06 christos Exp $	*/
2f3c74513SThomas Cort 
3f3c74513SThomas Cort /*
4f3c74513SThomas Cort  * Copyright (c) 1980, 1987, 1993
5f3c74513SThomas Cort  *	The Regents of the University of California.  All rights reserved.
6f3c74513SThomas Cort  *
7f3c74513SThomas Cort  * This code is derived from software contributed to Berkeley by
8f3c74513SThomas Cort  * Bob Toxen.
9f3c74513SThomas Cort  *
10f3c74513SThomas Cort  * Redistribution and use in source and binary forms, with or without
11f3c74513SThomas Cort  * modification, are permitted provided that the following conditions
12f3c74513SThomas Cort  * are met:
13f3c74513SThomas Cort  * 1. Redistributions of source code must retain the above copyright
14f3c74513SThomas Cort  *    notice, this list of conditions and the following disclaimer.
15f3c74513SThomas Cort  * 2. Redistributions in binary form must reproduce the above copyright
16f3c74513SThomas Cort  *    notice, this list of conditions and the following disclaimer in the
17f3c74513SThomas Cort  *    documentation and/or other materials provided with the distribution.
18f3c74513SThomas Cort  * 3. Neither the name of the University nor the names of its contributors
19f3c74513SThomas Cort  *    may be used to endorse or promote products derived from this software
20f3c74513SThomas Cort  *    without specific prior written permission.
21f3c74513SThomas Cort  *
22f3c74513SThomas Cort  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23f3c74513SThomas Cort  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24f3c74513SThomas Cort  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25f3c74513SThomas Cort  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26f3c74513SThomas Cort  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27f3c74513SThomas Cort  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28f3c74513SThomas Cort  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29f3c74513SThomas Cort  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30f3c74513SThomas Cort  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31f3c74513SThomas Cort  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32f3c74513SThomas Cort  * SUCH DAMAGE.
33f3c74513SThomas Cort  */
34f3c74513SThomas Cort 
35f3c74513SThomas Cort #include <sys/cdefs.h>
36f3c74513SThomas Cort #ifndef lint
37f3c74513SThomas Cort __COPYRIGHT("@(#) Copyright (c) 1980, 1987, 1993\
38f3c74513SThomas Cort  The Regents of the University of California.  All rights reserved.");
39f3c74513SThomas Cort #endif /* not lint */
40f3c74513SThomas Cort 
41f3c74513SThomas Cort #ifndef lint
42f3c74513SThomas Cort #if 0
43f3c74513SThomas Cort static char sccsid[] = "@(#)lock.c	8.1 (Berkeley) 6/6/93";
44f3c74513SThomas Cort #endif
45*84d9c625SLionel Sambuc __RCSID("$NetBSD: lock.c,v 1.33 2013/10/18 20:47:06 christos Exp $");
46f3c74513SThomas Cort #endif /* not lint */
47f3c74513SThomas Cort 
48f3c74513SThomas Cort /*
49f3c74513SThomas Cort  * Lock a terminal up until the given key is entered, until the root
50f3c74513SThomas Cort  * password is entered, or the given interval times out.
51f3c74513SThomas Cort  *
52f3c74513SThomas Cort  * Timeout interval is by default TIMEOUT, it can be changed with
53f3c74513SThomas Cort  * an argument of the form -time where time is in minutes
54f3c74513SThomas Cort  */
55f3c74513SThomas Cort 
56f3c74513SThomas Cort #include <sys/param.h>
57f3c74513SThomas Cort #include <sys/stat.h>
58f3c74513SThomas Cort #include <sys/time.h>
59f3c74513SThomas Cort #include <signal.h>
60f3c74513SThomas Cort 
61f3c74513SThomas Cort #include <err.h>
62f3c74513SThomas Cort #include <pwd.h>
63f3c74513SThomas Cort #include <errno.h>
64f3c74513SThomas Cort #include <stdio.h>
65f3c74513SThomas Cort #include <stdlib.h>
66f3c74513SThomas Cort #include <string.h>
67f3c74513SThomas Cort #include <termios.h>
68f3c74513SThomas Cort #include <time.h>
69f3c74513SThomas Cort #include <unistd.h>
70f3c74513SThomas Cort 
71f3c74513SThomas Cort #ifdef USE_PAM
72f3c74513SThomas Cort #include <security/pam_appl.h>
73f3c74513SThomas Cort #include <security/openpam.h>	/* for openpam_ttyconv() */
74f3c74513SThomas Cort #endif
75f3c74513SThomas Cort 
76f3c74513SThomas Cort #ifdef SKEY
77f3c74513SThomas Cort #include <skey.h>
78f3c74513SThomas Cort #endif
79f3c74513SThomas Cort 
80f3c74513SThomas Cort 
81f3c74513SThomas Cort #define	TIMEOUT	15
82f3c74513SThomas Cort 
83f3c74513SThomas Cort int	main(int, char **);
84f3c74513SThomas Cort 
85f3c74513SThomas Cort static void	bye(int) __dead;
86f3c74513SThomas Cort static void	hi(int);
87f3c74513SThomas Cort static void	quit(int) __dead;
88f3c74513SThomas Cort #ifdef SKEY
89f3c74513SThomas Cort static int	skey_auth(const char *);
90f3c74513SThomas Cort #endif
91f3c74513SThomas Cort 
92f3c74513SThomas Cort static struct timeval	timeout;
93f3c74513SThomas Cort static struct timeval	zerotime;
94f3c74513SThomas Cort static struct termios	tty, ntty;
95f3c74513SThomas Cort static int	notimeout;			/* no timeout at all */
96f3c74513SThomas Cort static long	nexttime;			/* keep the timeout time */
97f3c74513SThomas Cort 
98f3c74513SThomas Cort int
main(int argc,char ** argv)99f3c74513SThomas Cort main(int argc, char **argv)
100f3c74513SThomas Cort {
101f3c74513SThomas Cort 	struct passwd *pw;
102f3c74513SThomas Cort 	struct timeval timval;
103f3c74513SThomas Cort 	struct itimerval ntimer, otimer;
104f3c74513SThomas Cort 	struct tm *timp;
105f3c74513SThomas Cort 	time_t curtime;
106f3c74513SThomas Cort 	int ch, usemine;
107f3c74513SThomas Cort 	long sectimeout;
108*84d9c625SLionel Sambuc 	char *ap, *ttynam;
109f3c74513SThomas Cort 	const char *tzn;
110f3c74513SThomas Cort 	uid_t uid = getuid();
111f3c74513SThomas Cort 	char hostname[MAXHOSTNAMELEN + 1], s[BUFSIZ], s1[BUFSIZ];
112f3c74513SThomas Cort #ifdef USE_PAM
113f3c74513SThomas Cort 	pam_handle_t *pamh = NULL;
114f3c74513SThomas Cort 	static const struct pam_conv pamc = { &openpam_ttyconv, NULL };
115f3c74513SThomas Cort 	int pam_err;
116*84d9c625SLionel Sambuc #else
117*84d9c625SLionel Sambuc 	char *mypw = NULL;
118f3c74513SThomas Cort #endif
119f3c74513SThomas Cort 
120f3c74513SThomas Cort 	if ((pw = getpwuid(getuid())) == NULL)
121f3c74513SThomas Cort 		errx(1, "unknown uid %lu.", (u_long)uid);
122f3c74513SThomas Cort 
123f3c74513SThomas Cort 	notimeout = 0;
124f3c74513SThomas Cort 	sectimeout = TIMEOUT;
125f3c74513SThomas Cort 	usemine = 0;
126f3c74513SThomas Cort 
127f3c74513SThomas Cort 	while ((ch = getopt(argc, argv, "npt:")) != -1)
128f3c74513SThomas Cort 		switch ((char)ch) {
129f3c74513SThomas Cort 		case 'n':
130f3c74513SThomas Cort 			notimeout = 1;
131f3c74513SThomas Cort 			break;
132f3c74513SThomas Cort 		case 't':
133f3c74513SThomas Cort 			errno = 0;
134f3c74513SThomas Cort 			if (((sectimeout = strtol(optarg, &ap, 0)) == LONG_MAX
135f3c74513SThomas Cort 			    || sectimeout == LONG_MIN)
136f3c74513SThomas Cort 			    && errno == ERANGE)
137f3c74513SThomas Cort 				err(1, "illegal timeout value: %s", optarg);
138f3c74513SThomas Cort 			if (optarg == ap || *ap || sectimeout <= 0)
139f3c74513SThomas Cort 				errx(1, "illegal timeout value: %s", optarg);
140f3c74513SThomas Cort 			if (sectimeout >= INT_MAX / 60)
141f3c74513SThomas Cort 				errx(1, "too large timeout value: %ld",
142f3c74513SThomas Cort 				    sectimeout);
143f3c74513SThomas Cort 			break;
144f3c74513SThomas Cort 		case 'p':
145f3c74513SThomas Cort 			usemine = 1;
146f3c74513SThomas Cort #ifndef USE_PAM
147f3c74513SThomas Cort 			mypw = strdup(pw->pw_passwd);
148f3c74513SThomas Cort 			if (!mypw)
149f3c74513SThomas Cort 				err(1, "strdup");
150f3c74513SThomas Cort #endif
151f3c74513SThomas Cort 			break;
152f3c74513SThomas Cort 		case '?':
153f3c74513SThomas Cort 		default:
154f3c74513SThomas Cort 			(void)fprintf(stderr,
155f3c74513SThomas Cort 			    "usage: %s [-np] [-t timeout]\n", getprogname());
156f3c74513SThomas Cort 			exit(1);
157f3c74513SThomas Cort 		}
158f3c74513SThomas Cort 
159f3c74513SThomas Cort #if defined(USE_PAM) || defined(SKEY)
160f3c74513SThomas Cort 	if (! usemine) {	/* -p with PAM or S/key needs privs */
161f3c74513SThomas Cort #endif
162f3c74513SThomas Cort 	if (setuid(uid) == -1)	/* discard privs */
163f3c74513SThomas Cort 		err(1, "setuid failed");
164f3c74513SThomas Cort #if defined(USE_PAM) || defined(SKEY)
165f3c74513SThomas Cort 	}
166f3c74513SThomas Cort #endif
167f3c74513SThomas Cort 
168f3c74513SThomas Cort 	timeout.tv_sec = (int)sectimeout * 60;
169f3c74513SThomas Cort 
170f3c74513SThomas Cort 	if (tcgetattr(STDIN_FILENO, &tty) < 0)	/* get information for header */
171f3c74513SThomas Cort 		err(1, "tcgetattr failed");
172f3c74513SThomas Cort 	gethostname(hostname, sizeof(hostname));
173f3c74513SThomas Cort 	hostname[sizeof(hostname) - 1] = '\0';
174f3c74513SThomas Cort 	if (!(ttynam = ttyname(STDIN_FILENO)))
175f3c74513SThomas Cort 		err(1, "ttyname failed");
176f3c74513SThomas Cort 	if (gettimeofday(&timval, NULL) == -1)
177f3c74513SThomas Cort 		err(1, "gettimeofday failed");
178f3c74513SThomas Cort 	curtime = timval.tv_sec;
179f3c74513SThomas Cort 	nexttime = timval.tv_sec + ((int)sectimeout * 60);
180f3c74513SThomas Cort 	timp = localtime(&curtime);
181f3c74513SThomas Cort 	ap = asctime(timp);
182f3c74513SThomas Cort #ifdef __SVR4
183f3c74513SThomas Cort 	tzn = tzname[0];
184f3c74513SThomas Cort #else
185f3c74513SThomas Cort 	tzn = timp->tm_zone;
186f3c74513SThomas Cort #endif
187f3c74513SThomas Cort 
188f3c74513SThomas Cort 	if (signal(SIGINT, quit) == SIG_ERR)
189f3c74513SThomas Cort 		err(1, "signal failed");
190f3c74513SThomas Cort 	if (signal(SIGQUIT, quit) == SIG_ERR)
191f3c74513SThomas Cort 		err(1, "signal failed");
192f3c74513SThomas Cort 	ntty = tty; ntty.c_lflag &= ~ECHO;
193f3c74513SThomas Cort 	if (tcsetattr(STDIN_FILENO, TCSADRAIN, &ntty) == -1)
194f3c74513SThomas Cort 		err(1, "tcsetattr");
195f3c74513SThomas Cort 
196f3c74513SThomas Cort 	if (!usemine) {
197f3c74513SThomas Cort 		/* get key and check again */
198f3c74513SThomas Cort 		(void)printf("Key: ");
199f3c74513SThomas Cort 		if (!fgets(s, sizeof(s), stdin) || *s == '\n')
200f3c74513SThomas Cort 			quit(0);
201f3c74513SThomas Cort 		(void)printf("\nAgain: ");
202f3c74513SThomas Cort 		/*
203f3c74513SThomas Cort 		 * Don't need EOF test here, if we get EOF, then s1 != s
204f3c74513SThomas Cort 		 * and the right things will happen.
205f3c74513SThomas Cort 		 */
206f3c74513SThomas Cort 		(void)fgets(s1, sizeof(s1), stdin);
207f3c74513SThomas Cort 		(void)putchar('\n');
208f3c74513SThomas Cort 		if (strcmp(s1, s)) {
209f3c74513SThomas Cort 			(void)printf("\alock: passwords didn't match.\n");
210f3c74513SThomas Cort 			(void)tcsetattr(STDIN_FILENO, TCSADRAIN, &tty);
211f3c74513SThomas Cort 			exit(1);
212f3c74513SThomas Cort 		}
213f3c74513SThomas Cort 		s[0] = '\0';
214*84d9c625SLionel Sambuc #ifndef USE_PAM
215f3c74513SThomas Cort 		mypw = s1;
216*84d9c625SLionel Sambuc #endif
217f3c74513SThomas Cort 	}
218f3c74513SThomas Cort #ifdef USE_PAM
219f3c74513SThomas Cort 	if (usemine) {
220f3c74513SThomas Cort 		pam_err = pam_start("lock", pw->pw_name, &pamc, &pamh);
221f3c74513SThomas Cort 		if (pam_err != PAM_SUCCESS)
222f3c74513SThomas Cort 			err(1, "pam_start: %s", pam_strerror(NULL, pam_err));
223f3c74513SThomas Cort 	}
224f3c74513SThomas Cort #endif
225f3c74513SThomas Cort 
226f3c74513SThomas Cort 	/* set signal handlers */
227f3c74513SThomas Cort 	if (signal(SIGINT, hi) == SIG_ERR)
228f3c74513SThomas Cort 		err(1, "signal failed");
229f3c74513SThomas Cort 	if (signal(SIGQUIT, hi) == SIG_ERR)
230f3c74513SThomas Cort 		err(1, "signal failed");
231f3c74513SThomas Cort 	if (signal(SIGTSTP, hi) == SIG_ERR)
232f3c74513SThomas Cort 		err(1, "signal failed");
233f3c74513SThomas Cort 
234f3c74513SThomas Cort 	if (notimeout) {
235f3c74513SThomas Cort 		if (signal(SIGALRM, hi) == SIG_ERR)
236f3c74513SThomas Cort 			err(1, "signal failed");
237f3c74513SThomas Cort 		(void)printf("lock: %s on %s.  no timeout.\n"
238f3c74513SThomas Cort 		    "time now is %.20s%s%s",
239f3c74513SThomas Cort 		    ttynam, hostname, ap, tzn, ap + 19);
240f3c74513SThomas Cort 	}
241f3c74513SThomas Cort 	else {
242f3c74513SThomas Cort 		if (signal(SIGALRM, bye) == SIG_ERR)
243f3c74513SThomas Cort 			err(1, "signal failed");
244f3c74513SThomas Cort 
245f3c74513SThomas Cort 		ntimer.it_interval = zerotime;
246f3c74513SThomas Cort 		ntimer.it_value = timeout;
247f3c74513SThomas Cort 		if (setitimer(ITIMER_REAL, &ntimer, &otimer) == -1)
248f3c74513SThomas Cort 			err(1, "setitimer failed");
249f3c74513SThomas Cort 
250f3c74513SThomas Cort 		/* header info */
251f3c74513SThomas Cort 		(void)printf("lock: %s on %s. timeout in %ld minutes\n"
252f3c74513SThomas Cort 		    "time now is %.20s%s%s",
253f3c74513SThomas Cort 		    ttynam, hostname, sectimeout, ap, tzn, ap + 19);
254f3c74513SThomas Cort 	}
255f3c74513SThomas Cort 
256f3c74513SThomas Cort 	for (;;) {
257f3c74513SThomas Cort #ifdef USE_PAM
258f3c74513SThomas Cort 		if (usemine) {
259f3c74513SThomas Cort 			pam_err = pam_authenticate(pamh, 0);
260f3c74513SThomas Cort 			if (pam_err == PAM_SUCCESS)
261f3c74513SThomas Cort 				break;
262f3c74513SThomas Cort 			goto tryagain;
263f3c74513SThomas Cort 		}
264f3c74513SThomas Cort #endif
265f3c74513SThomas Cort 		(void)printf("Key: ");
266f3c74513SThomas Cort 		if (!fgets(s, sizeof(s), stdin)) {
267f3c74513SThomas Cort 			clearerr(stdin);
268f3c74513SThomas Cort 			hi(0);
269f3c74513SThomas Cort 			goto tryagain;
270f3c74513SThomas Cort 		}
271f3c74513SThomas Cort #ifndef USE_PAM
272f3c74513SThomas Cort 		if (usemine) {
273f3c74513SThomas Cort 			s[strlen(s) - 1] = '\0';
274f3c74513SThomas Cort #ifdef SKEY
275f3c74513SThomas Cort 			if (strcasecmp(s, "s/key") == 0) {
276f3c74513SThomas Cort 				if (skey_auth(pw->pw_name))
277f3c74513SThomas Cort 					break;
278f3c74513SThomas Cort 			}
279f3c74513SThomas Cort #endif
280f3c74513SThomas Cort 			if (!strcmp(mypw, crypt(s, mypw)))
281f3c74513SThomas Cort 				break;
282f3c74513SThomas Cort 		}
283f3c74513SThomas Cort 		else
284f3c74513SThomas Cort #endif
285f3c74513SThomas Cort 			if (!strcmp(s, s1))
286f3c74513SThomas Cort 				break;
287f3c74513SThomas Cort 		(void)printf("\a\n");
288f3c74513SThomas Cort  tryagain:
289f3c74513SThomas Cort 		if (tcsetattr(STDIN_FILENO, TCSADRAIN, &ntty) == -1
290f3c74513SThomas Cort 		    && errno != EINTR)
291f3c74513SThomas Cort 			err(1, "tcsetattr failed");
292f3c74513SThomas Cort 	}
293f3c74513SThomas Cort #ifdef USE_PAM
294f3c74513SThomas Cort 	if (usemine) {
295f3c74513SThomas Cort 		(void)pam_end(pamh, pam_err);
296f3c74513SThomas Cort 	}
297f3c74513SThomas Cort #endif
298f3c74513SThomas Cort 	quit(0);
299f3c74513SThomas Cort 	/* NOTREACHED */
300f3c74513SThomas Cort 	return 0;
301f3c74513SThomas Cort }
302f3c74513SThomas Cort 
303f3c74513SThomas Cort #ifdef SKEY
304f3c74513SThomas Cort /*
305f3c74513SThomas Cort  * We can't use libskey's skey_authenticate() since it
306f3c74513SThomas Cort  * handles signals in a way that's inappropriate
307f3c74513SThomas Cort  * for our needs. Instead we roll our own.
308f3c74513SThomas Cort  */
309f3c74513SThomas Cort static int
skey_auth(const char * user)310f3c74513SThomas Cort skey_auth(const char *user)
311f3c74513SThomas Cort {
312f3c74513SThomas Cort 	char s[128];
313f3c74513SThomas Cort 	const char *ask;
314f3c74513SThomas Cort 	int ret = 0;
315f3c74513SThomas Cort 
316f3c74513SThomas Cort 	if (!skey_haskey(user) && (ask = skey_keyinfo(user))) {
317f3c74513SThomas Cort 		(void)printf("\n[%s]\nResponse: ", ask);
318f3c74513SThomas Cort 		if (!fgets(s, sizeof(s), stdin) || *s == '\n')
319f3c74513SThomas Cort 			clearerr(stdin);
320f3c74513SThomas Cort 		else {
321f3c74513SThomas Cort 			s[strlen(s) - 1] = '\0';
322f3c74513SThomas Cort 			if (skey_passcheck(user, s) != -1)
323f3c74513SThomas Cort 				ret = 1;
324f3c74513SThomas Cort 		}
325f3c74513SThomas Cort 	} else
326f3c74513SThomas Cort 		(void)printf("Sorry, you have no s/key.\n");
327f3c74513SThomas Cort 	return ret;
328f3c74513SThomas Cort }
329f3c74513SThomas Cort #endif
330f3c74513SThomas Cort 
331f3c74513SThomas Cort static void
hi(int dummy)332f3c74513SThomas Cort hi(int dummy)
333f3c74513SThomas Cort {
334f3c74513SThomas Cort 	struct timeval timval;
335f3c74513SThomas Cort 
336f3c74513SThomas Cort 	if (notimeout)
337f3c74513SThomas Cort 		(void)printf("lock: type in the unlock key.\n");
338f3c74513SThomas Cort 	else {
339f3c74513SThomas Cort 		if (gettimeofday(&timval, NULL) == -1)
340f3c74513SThomas Cort 			err(1, "gettimeofday failed");
341f3c74513SThomas Cort 		(void)printf("lock: type in the unlock key. "
342f3c74513SThomas Cort 		    "timeout in %lld:%lld minutes\n",
343f3c74513SThomas Cort 		    (long long)(nexttime - timval.tv_sec) / 60,
344f3c74513SThomas Cort 		    (long long)(nexttime - timval.tv_sec) % 60);
345f3c74513SThomas Cort 	}
346f3c74513SThomas Cort }
347f3c74513SThomas Cort 
348f3c74513SThomas Cort static void
quit(int dummy)349f3c74513SThomas Cort quit(int dummy)
350f3c74513SThomas Cort {
351f3c74513SThomas Cort 	(void)putchar('\n');
352f3c74513SThomas Cort 	(void)tcsetattr(STDIN_FILENO, TCSADRAIN, &tty);
353f3c74513SThomas Cort 	exit(0);
354f3c74513SThomas Cort }
355f3c74513SThomas Cort 
356f3c74513SThomas Cort static void
bye(int dummy)357f3c74513SThomas Cort bye(int dummy)
358f3c74513SThomas Cort {
359f3c74513SThomas Cort 	(void)tcsetattr(STDIN_FILENO, TCSADRAIN, &tty);
360f3c74513SThomas Cort 	(void)printf("lock: timeout\n");
361f3c74513SThomas Cort 	exit(1);
362f3c74513SThomas Cort }
363