1 /* $NetBSD: lock.c,v 1.24 2004/07/13 11:55:02 wiz 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.24 2004/07/13 11:55:02 wiz 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 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