1 /* $NetBSD: lock.c,v 1.25 2006/05/11 12:02:08 liamjfoy 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.25 2006/05/11 12:02:08 liamjfoy 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 <ctype.h> 62 #include <err.h> 63 #include <pwd.h> 64 #include <errno.h> 65 #include <stdio.h> 66 #include <stdlib.h> 67 #include <string.h> 68 #include <termios.h> 69 #include <time.h> 70 #include <unistd.h> 71 #ifdef SKEY 72 #include <skey.h> 73 #endif 74 75 #define TIMEOUT 15 76 77 int main __P((int, char **)); 78 79 static void bye(int) __attribute__((__noreturn__)); 80 static void hi(int); 81 static void quit(int) __attribute__((__noreturn__)); 82 #ifdef SKEY 83 static int skey_auth(const char *); 84 #endif 85 86 static struct timeval timeout; 87 static struct timeval zerotime; 88 static struct termios tty, ntty; 89 static int notimeout; /* no timeout at all */ 90 static long nexttime; /* keep the timeout time */ 91 92 int 93 main(int argc, char **argv) 94 { 95 struct passwd *pw; 96 struct timeval timval; 97 struct itimerval ntimer, otimer; 98 struct tm *timp; 99 time_t curtime; 100 int ch, usemine; 101 long sectimeout; 102 char *ap, *mypw, *ttynam; 103 const char *tzn; 104 uid_t uid = getuid(); 105 char hostname[MAXHOSTNAMELEN + 1], s[BUFSIZ], s1[BUFSIZ]; 106 107 if ((pw = getpwuid(getuid())) == NULL) 108 errx(1, "unknown uid %lu.", (u_long)uid); 109 110 if (setuid(uid) == -1) /* discard privs */ 111 err(1, "setuid failed"); 112 113 notimeout = 0; 114 sectimeout = TIMEOUT; 115 mypw = NULL; 116 usemine = 0; 117 118 while ((ch = getopt(argc, argv, "npt:")) != -1) 119 switch ((char)ch) { 120 case 'n': 121 notimeout = 1; 122 break; 123 case 't': 124 errno = 0; 125 if (((sectimeout = strtol(optarg, &ap, 0)) == LONG_MAX 126 || sectimeout == LONG_MIN) 127 && errno == ERANGE) 128 err(1, "illegal timeout value: %s", optarg); 129 if (optarg == ap || *ap || sectimeout <= 0) 130 errx(1, "illegal timeout value: %s", optarg); 131 if (sectimeout >= INT_MAX / 60) 132 errx(1, "too large timeout value: %ld", 133 sectimeout); 134 break; 135 case 'p': 136 usemine = 1; 137 mypw = strdup(pw->pw_passwd); 138 if (!mypw) 139 err(1, "strdup"); 140 break; 141 case '?': 142 default: 143 (void)fprintf(stderr, 144 "usage: %s [-np] [-t timeout]\n", getprogname()); 145 exit(1); 146 } 147 timeout.tv_sec = (int)sectimeout * 60; 148 149 if (tcgetattr(STDIN_FILENO, &tty) < 0) /* get information for header */ 150 err(1, "tcgetattr failed"); 151 gethostname(hostname, sizeof(hostname)); 152 hostname[sizeof(hostname) - 1] = '\0'; 153 if (!(ttynam = ttyname(STDIN_FILENO))) 154 err(1, "ttyname failed"); 155 if (gettimeofday(&timval, NULL) == -1) 156 err(1, "gettimeofday failed"); 157 curtime = timval.tv_sec; 158 nexttime = timval.tv_sec + ((int)sectimeout * 60); 159 timp = localtime(&curtime); 160 ap = asctime(timp); 161 #ifdef __SVR4 162 tzn = tzname[0]; 163 #else 164 tzn = timp->tm_zone; 165 #endif 166 167 if (signal(SIGINT, quit) == SIG_ERR) 168 err(1, "signal failed"); 169 if (signal(SIGQUIT, quit) == SIG_ERR) 170 err(1, "signal failed"); 171 ntty = tty; ntty.c_lflag &= ~ECHO; 172 if (tcsetattr(STDIN_FILENO, TCSADRAIN, &ntty) == -1) 173 err(1, "tcsetattr"); 174 175 if (!mypw) { 176 /* get key and check again */ 177 (void)printf("Key: "); 178 if (!fgets(s, sizeof(s), stdin) || *s == '\n') 179 quit(0); 180 (void)printf("\nAgain: "); 181 /* 182 * Don't need EOF test here, if we get EOF, then s1 != s 183 * and the right things will happen. 184 */ 185 (void)fgets(s1, sizeof(s1), stdin); 186 (void)putchar('\n'); 187 if (strcmp(s1, s)) { 188 (void)printf("\alock: passwords didn't match.\n"); 189 (void)tcsetattr(STDIN_FILENO, TCSADRAIN, &tty); 190 exit(1); 191 } 192 s[0] = '\0'; 193 mypw = s1; 194 } 195 196 /* set signal handlers */ 197 if (signal(SIGINT, hi) == SIG_ERR) 198 err(1, "signal failed"); 199 if (signal(SIGQUIT, hi) == SIG_ERR) 200 err(1, "signal failed"); 201 if (signal(SIGTSTP, hi) == SIG_ERR) 202 err(1, "signal failed"); 203 204 if (notimeout) { 205 if (signal(SIGALRM, hi) == SIG_ERR) 206 err(1, "signal failed"); 207 (void)printf("lock: %s on %s. no timeout.\n" 208 "time now is %.20s%s%s", 209 ttynam, hostname, ap, tzn, ap + 19); 210 } 211 else { 212 if (signal(SIGALRM, bye) == SIG_ERR) 213 err(1, "signal failed"); 214 215 ntimer.it_interval = zerotime; 216 ntimer.it_value = timeout; 217 if (setitimer(ITIMER_REAL, &ntimer, &otimer) == -1) 218 err(1, "setitimer failed"); 219 220 /* header info */ 221 (void)printf("lock: %s on %s. timeout in %ld minutes\n" 222 "time now is %.20s%s%s", 223 ttynam, hostname, sectimeout, ap, tzn, ap + 19); 224 } 225 226 for (;;) { 227 (void)printf("Key: "); 228 if (!fgets(s, sizeof(s), stdin)) { 229 clearerr(stdin); 230 hi(0); 231 goto tryagain; 232 } 233 if (usemine) { 234 s[strlen(s) - 1] = '\0'; 235 #ifdef SKEY 236 if (strcasecmp(s, "s/key") == 0) { 237 if (skey_auth(pw->pw_name)) 238 break; 239 } 240 #endif 241 if (!strcmp(mypw, crypt(s, mypw))) 242 break; 243 } 244 else if (!strcmp(s, s1)) 245 break; 246 (void)printf("\a\n"); 247 tryagain: 248 if (tcsetattr(STDIN_FILENO, TCSADRAIN, &ntty) == -1 249 && errno != EINTR) 250 err(1, "tcsetattr failed"); 251 } 252 quit(0); 253 /* NOTREACHED */ 254 return 0; 255 } 256 257 #ifdef SKEY 258 /* 259 * We can't use libskey's skey_authenticate() since it 260 * handles signals in a way that's inappropriate 261 * for our needs. Instead we roll our own. 262 */ 263 static int 264 skey_auth(const char *user) 265 { 266 char s[128]; 267 const char *ask; 268 int ret = 0; 269 270 if (!skey_haskey(user) && (ask = skey_keyinfo(user))) { 271 (void)printf("\n[%s]\nResponse: ", ask); 272 if (!fgets(s, sizeof(s), stdin) || *s == '\n') 273 clearerr(stdin); 274 else { 275 s[strlen(s) - 1] = '\0'; 276 if (skey_passcheck(user, s) != -1) 277 ret = 1; 278 } 279 } else 280 (void)printf("Sorry, you have no s/key.\n"); 281 return ret; 282 } 283 #endif 284 285 static void 286 hi(dummy) 287 int dummy; 288 { 289 struct timeval timval; 290 291 if (notimeout) 292 (void)printf("lock: type in the unlock key.\n"); 293 else { 294 if (gettimeofday(&timval, NULL) == -1) 295 err(1, "gettimeofday failed"); 296 (void)printf("lock: type in the unlock key. " 297 "timeout in %ld:%ld minutes\n", 298 (nexttime - timval.tv_sec) / 60, 299 (nexttime - timval.tv_sec) % 60); 300 } 301 } 302 303 static void 304 quit(int dummy) 305 { 306 (void)putchar('\n'); 307 (void)tcsetattr(STDIN_FILENO, TCSADRAIN, &tty); 308 exit(0); 309 } 310 311 static void 312 bye(int dummy) 313 { 314 (void)tcsetattr(STDIN_FILENO, TCSADRAIN, &tty); 315 (void)printf("lock: timeout\n"); 316 exit(1); 317 } 318