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