1 /*-
2 * Copyright (c) 1998-2010 Joe Marcus Clarke <marcus@marcuscom.com>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * Gone - a terminal locking program with many improvements over lock(1)
27 *
28 * $MCom: gone/gone.c,v 1.10 2010/08/01 16:09:18 marcus Exp $
29 */
30
31 #include "config.h"
32 #include <stdlib.h> /* atoi() */
33 #include <stdio.h> /* fprintf(), stderr, printf(), fgets(), stdin, BUFSIZ, fflush(), putchar(), clearerr() */
34 #include <signal.h> /* signal(), SIGINT, SIGSTP, SIGQUIT, SIGALRM, SIGHUP, kill() */
35 #include <unistd.h> /* getpass(), getuid(), getppid(), STDIN_FILENO, setuid() */
36 #include <ctype.h> /* isdigit() */
37 #ifdef HAVE_CRYPT_H
38 #include <crypt.h>
39 #endif
40 #ifdef HAVE_SYS_STAT_H
41 #include <sys/stat.h> /* struct timeval, struct itimerval, chmod(), gettimeofday(), localtime(), asctime(), setitimer(), stat(), struct stat */
42 #endif
43 #ifdef HAVE_SYS_IOCTL_H
44 #include <sys/ioctl.h>
45 #endif
46 #ifdef HAVE_SYS_TERMIO_H
47 #include <sys/termio.h> /* struct termio, TCGETA, ECHO, TCSETAF, TCSETA, TCGETA, ioctl() */
48 #endif
49 #ifdef HAVE_SYS_TIME_H
50 #include <sys/time.h>
51 #endif
52 #ifdef HAVE_SYS_PARAM_H
53 #include <sys/param.h>
54 #endif
55 #ifdef HAVE_SYS_CONSIO_H
56 #include <sys/consio.h>
57 #endif
58 #ifdef HAVE_STRING_H
59 #include <string.h>
60 #endif
61 #ifdef HAVE_ERRNO_H
62 #include <errno.h>
63 #endif
64 #ifdef HAVE_TERMIOS_H
65 #include <termios.h>
66 #endif
67 #ifdef HAVE_TIME_H
68 #include <time.h>
69 #endif
70 #if defined(OSF1) && defined(EN_SEC)
71 #include <sys/security.h>
72 #include <prot.h>
73 #endif
74 #ifdef HAVE_SYS_TYPES_H
75 #include <sys/types.h>
76 #endif
77 #ifdef HAVE_PWD_H
78 #include <pwd.h>
79 #endif
80
81 #include "gone.h"
82
83 #define TIMEOUT 10
84 #ifdef _PASSWORD_LEN
85 #define PASSWORD_BUFFER _PASSWORD_LEN
86 #else
87 #define PASSWORD_BUFFER 128
88 #endif
89
90 #if defined OSF1 || defined ULTRIX
91 struct timeval timeout = {0, 0};
92 struct timeval zerotime = {0, 0};
93 #else /* OSF1 || ULTRIX */
94 struct timeval timeout;
95 struct timeval zerotime;
96 #endif /* OSF1 || ULTRIX */
97 #define SALT "3C" /* XXX Crappy */
98 struct stat ttystat;
99 long nexttime;
100 mode_t ttymode;
101 char *ttynam;
102 static int vtylocked = 0;
103
104 /* Function prototypes */
105 void lockTerm(char *ap, char *password, int timeAway,
106 int extendedCommands, int printBanner);
107 char *getPassword();
108 void usage(char *progName);
109 void quit();
110 void hi();
111 void printHeader(int extendedCommands, int printBanner);
112 void print_version_info(void);
113 void unlockVty(void);
114
115 struct gone_commands commands[] =
116 {
117 {"w", "Print a summary of current system activity", 1},
118 {"finger", "Display user information", 1},
119 {"whoami", "Display the the locking user's name", 1},
120 {"help", "Print this message", 0},
121 {"date", "Display the date and time", 1},
122 {"status", "Display the lock timeout", 0},
123 {"cls", "Clear the screen, and display this message", 0}
124 };
125
126 #if defined(ULTRIX)
127 extern char *optarg;
128 extern int optind, opterr;
129 #endif /* ULTRIX */
130
131 int
main(int argc,char * argv[])132 main(int argc, char *argv[]) {
133 #if !defined(HAVE_ERRNO_H)
134 extern int errno;
135 #endif
136 char *ap;
137 char buffer[PASSWORD_BUFFER];
138 char *cryptBuffer;
139 char *cryptRetypeBuffer;
140 char enteredPass[PASSWORD_BUFFER];
141 struct timeval timval;
142 struct itimerval ntimer, otimer;
143 struct tm *timp;
144 int goneTime;
145 int ch;
146 int mesgOff = 1;
147 int extendedCommands = 1;
148 int printBanner = 1;
149 int lockvty = 0;
150 #if defined(SETUID)
151 int useSysPasswd = 0;
152 char *sysPass;
153 struct passwd *pw;
154 #endif
155
156 goneTime = TIMEOUT;
157 #if defined(OSF1) && defined(EN_SEC) && defined(SETUID)
158 set_auth_parameters();
159 while ((ch = getopt(argc, argv, "bvpxynlt:")) != -1)
160 #elif defined(SETUID)
161 while ((ch = getopt(argc, argv, "bvpxynlt:")) != -1)
162 #else /* OSF1 && EN_SEC && SETUID */
163 while ((ch = getopt(argc, argv, "bvyxnlt:")) != -1)
164 #endif /* OSF1 && EN_SEC && SETUID */
165 switch((char)ch) {
166 case 'b':
167 printBanner = 0;
168 break;
169 case 'v':
170 print_version_info();
171 exit(0);
172 #if defined(OSF1) && defined(EN_SEC) && defined(SETUID)
173 case 'p':
174 if (getespwuid(getuid()) == NULL) {
175 printf("Error getting your password from the system.\n");
176 useSysPasswd = 0;
177 }
178 else {
179 sysPass = getespwuid(getuid())->ufld->fd_encrypt;
180 useSysPasswd = 1;
181 }
182 break;
183 #elif defined(SETUID)
184 case 'p':
185 if (!(pw = getpwuid(getuid()))) {
186 printf("Error getting your password from the system.\n");
187 useSysPasswd = 0;
188 }
189 else {
190 sysPass = pw->pw_passwd;
191 useSysPasswd = 1;
192 }
193 break;
194 #endif /* OSF1 && EN_SEC && SETUID */
195 case 'n':
196 case 'x':
197 extendedCommands = 0;
198 break;
199 case 'y':
200 mesgOff = 0;
201 break;
202 case 'l':
203 lockvty = 1;
204 break;
205 case 't':
206 if ((goneTime = atoi(optarg)) < 0) {
207 /* If goneTime == 0, then lock the
208 terminal indifinitely. */
209 fprintf(stderr, "Illegal timeout value.\n");
210 exit(1);
211 }
212 break;
213 default:
214 usage(argv[0]);
215 }
216
217 setuid(getuid()); /* reset uid permissions */
218 putenv("PATH=/bin:/usr/bin:/usr/bsd:/usr/ucb");
219
220 if (!(ttynam = ttyname(STDIN_FILENO))) { /* check to see if stdin is a tty */
221 printf("Not a terminal\n");
222 exit(1);
223 }
224 stat(ttynam, &ttystat); /* save current tty permissions */
225 ttymode = ttystat.st_mode;
226 if (mesgOff == 1) {
227 chmod(ttynam, 00600); /* chmod the tty so only the owner can read and write to it */
228 }
229 else {
230 #ifdef IRIX
231 /* Dumb IRIX "security" */
232 chmod(ttynam, 00622);
233 #else /* IRIX */
234 chmod(ttynam, 00620);
235 #endif /* IRIX */
236 }
237
238 timeout.tv_sec = goneTime * 60;
239
240 if (gettimeofday(&timval,(struct timezone *)NULL)) {
241 exit(1);
242 }
243
244 nexttime = timval.tv_sec + (goneTime * 60);
245 timp = localtime((time_t *)&timval.tv_sec);
246 ap = asctime(timp);
247
248
249 ntimer.it_interval = zerotime;
250 ntimer.it_value = timeout;
251
252 if ( goneTime != 0 ) {
253 /* Allow for the terminal to be locked forever. */
254 setitimer(ITIMER_REAL, &ntimer, &otimer);
255 }
256
257
258 if (gettimeofday(&timval,(struct timezone *)NULL)) {
259 exit(1);
260 }
261
262 nexttime = timval.tv_sec + (goneTime * 60);
263 timp = localtime((time_t *)&timval.tv_sec);
264 ap = asctime(timp);
265
266 ntimer.it_interval = zerotime;
267 ntimer.it_value = timeout;
268
269 if ( goneTime != 0 ) {
270 /* Allow for the terminal to be locked forever. */
271 setitimer(ITIMER_REAL, &ntimer, &otimer);
272 }
273
274 #if defined(SETUID)
275 if (useSysPasswd) {
276 strncpy(enteredPass,sysPass, PASSWORD_BUFFER);
277 } else
278 #endif
279 {
280 strncpy(buffer, getpass("Password: "), PASSWORD_BUFFER);
281
282 if (*buffer == '\0') {
283 printf("Empty passwords are not allowed!\n");
284 exit(1);
285 }
286 cryptBuffer = (char *)crypt(buffer, SALT);
287 strncpy(enteredPass, cryptBuffer, PASSWORD_BUFFER);
288 memset(buffer, '\0', sizeof(buffer));
289
290 strncpy(buffer, getpass("Retype: "), PASSWORD_BUFFER);
291 cryptRetypeBuffer = (char *)crypt(buffer, SALT);
292 memset(buffer, '\0', sizeof(buffer));
293 fflush(stdin);
294
295 if (strcmp(enteredPass, cryptRetypeBuffer)) {
296 printf("Passwords did not match!\n");
297 exit(1);
298 }
299 }
300 /* Lock the vty if possible */
301 #ifdef VT_LOCKSWITCH
302 if (lockvty) {
303 if (ioctl(0, VT_LOCKSWITCH, &lockvty) == -1) {
304 printf("Failed to prevent VTY switching: %s\n", strerror(errno));
305 exit(1);
306 }
307 vtylocked = 1;
308 }
309 #else
310 printf("VTY locking is not supported on this platform.\n");
311 #endif
312
313 /* set signal handlers */
314 signal(SIGINT, (void (*)(int))hi);
315 signal(SIGQUIT, (void (*)(int))hi);
316 signal(SIGTSTP, (void (*)(int))hi);
317 signal(SIGALRM, (void (*)(int))quit);
318 signal(SIGHUP, (void (*)(int))quit);
319 lockTerm(ap, enteredPass, goneTime, extendedCommands, printBanner);
320
321 return 0;
322 }
323
lockTerm(char * ap,char * password,int timeAway,int extendedCommands,int printBanner)324 void lockTerm(char *ap, char *password, int timeAway,
325 int extendedCommands, int printBanner) {
326 char key[PASSWORD_BUFFER];
327 char *cryptKey;
328 char cmd[BUFSIZ];
329 int badPass = 1;
330 int goodCommand;
331 int i;
332
333
334 if ( timeAway == 0 ) {
335 printf("Terminal locked at %s indefinitely.\n", ap);
336 }
337 else {
338 printf("Terminal locked at %s for %d minutes(s).\n", ap, timeAway);
339 }
340
341 printHeader(extendedCommands, printBanner);
342 fflush(stdin);
343 printf("> ");
344
345 while(badPass) {
346 fflush(stdin);
347 if (!fgets(cmd, sizeof(cmd), stdin)) {
348 clearerr(stdin);
349 continue;
350 }
351 goodCommand = 0;
352 cmd[strlen(cmd) - 1] = '\0';
353 if (!strcmp(cmd, "help")) {
354 printHeader(extendedCommands, printBanner);
355 }
356 else if (!strcmp(cmd, "cls")) {
357 system("clear");
358 printHeader(extendedCommands, printBanner);
359 }
360 else if (!strcmp(cmd, "status")) {
361 hi();
362 }
363 else if (extendedCommands && !strcmp(cmd, "finger")) {
364 char fingerCommand[129] = "finger ";
365 char hostname[120];
366 char parsedHostname[120];
367 memset(hostname, '\0', sizeof(hostname));
368 memset(parsedHostname, '\0', sizeof(parsedHostname));
369 printf("Enter parameters: ");
370 if (!fgets(hostname, sizeof(hostname), stdin)) {
371 clearerr(stdin);
372 continue;
373 }
374 sscanf(hostname, "%[^]^#~()[\\\x0A\xFF\"'|`<>*?&$;,]", parsedHostname);
375 strncat(fingerCommand, parsedHostname, sizeof(fingerCommand) - 1);
376 system(fingerCommand);
377 }
378
379 else {
380 for (i = 0; i < sizeof(commands)/sizeof(commands[0]); i++) {
381 if (extendedCommands && !strcmp(cmd, commands[i].command)) {
382 system(commands[i].command);
383 goodCommand = 1;
384 }
385 }
386 }
387 if (!goodCommand && strcmp(cmd, "unlock") && strcmp(cmd, "") && strcmp(cmd, "help") && strcmp(cmd, "cls") && (!extendedCommands || strcmp(cmd, "finger")) && strcmp(cmd, "status")) {
388 printf("%s: command not allowed in lock mode\n", cmd);
389 printf("Type 'help' for a list of commands.\n");
390 }
391 if (strcmp(cmd, "unlock") || cmd[0] == '\0') printf("> ");
392 else {
393 strncpy(key, getpass("Enter password: "), PASSWORD_BUFFER);
394 #if defined(OSF1) && defined(EN_SEC) && defined(SETUID)
395 cryptKey = (char *)bigcrypt(key, password);
396 #else /* OSF1 && EN_SEC && SETUID */
397 cryptKey = (char *)crypt(key, password);
398 #endif /* OSF1 && EN_SEC && SETUID */
399 if (strcmp(cryptKey, password)) printf("Incorrect password!\n> ");
400 else {
401 chmod(ttynam, ttymode); /* reset tty permissions */
402 badPass = 0;
403 }
404 }
405 }
406
407 unlockVty();
408
409 exit(0);
410
411 }
412
413
usage(char * progName)414 void usage(char *progName) {
415 #ifdef SETUID
416 printf("Usage: %s [-v] [-p] [-x] [-l] [-y] [-t timeout] [Gone message]\n", progName);
417 #else /* SETUID */
418 printf("Usage: %s [-v] [-x] [-l] [-y] [-t timeout] [Gone message]\n", progName);
419 #endif /* SETUID */
420 exit(1);
421 }
422
quit()423 void quit() { /* log users out by killing their shell */
424 unlockVty();
425 kill(getppid(), SIGKILL);
426 exit(0);
427 }
428
429
printHeader(int extendedCommands,int printBanner)430 void printHeader(int extendedCommands, int printBanner) {
431 int i;
432
433 if (printBanner) {
434 printf("\n\n\n");
435 printf(" XXXXX XX X X X XXXXX XXXXX\n");
436 printf(" X X X X X X X X\n");
437 printf(" X X X X X X XXXXX XXX\n");
438 printf(" X X X X X X X X\n");
439 printf(" XXXXX X XX XXXXXX XXXXX XXXXX\n");
440 }
441 printf("\n");
442
443 printf("Available commands: \n");
444 for(i = 0; i < sizeof(commands)/sizeof(commands[0]); i++) {
445 if (extendedCommands || !commands[i].extended) {
446 printf("\t%-8s : %s\n", commands[i].command, commands[i].help_str);
447 }
448 }
449 printf("\n\tType unlock to unlock the terminal\n\n");
450 }
451
452 void
hi()453 hi() {
454 struct timeval timval;
455
456 #ifdef IRIX
457 signal(SIGINT, (void (*)(int))hi);
458 signal(SIGQUIT, (void (*)(int))hi);
459 signal(SIGTSTP, (void (*)(int))hi);
460 signal(SIGALRM, (void (*)(int))quit);
461 signal(SIGHUP, (void (*)(int))quit);
462 #endif /* IRIX */
463
464 if (!gettimeofday(&timval,(struct timezone *)NULL)) {
465 printf("\nTerminal locked!\nType 'help' for a list of commands\n\n");
466 if ( nexttime - timval.tv_sec >= 0 ) {
467 printf("Timeout in %ld minutes and %ld seconds\n", (nexttime - timval.tv_sec)/60, (nexttime - timval.tv_sec)%60);
468 }
469 else {
470 printf("Terminal locked indefinitely.\n");
471 printf("Terminal has been locked for %ld minutes and %ld seconds.\n", (timval.tv_sec - nexttime)/60, (timval.tv_sec - nexttime)%60);
472 }
473 }
474 }
475
print_version_info(void)476 void print_version_info(void) {
477 printf("Gone version %s by Joe Marcus Clarke.\n", VERSION);
478 printf("\t* Gone compiled on %s at %s for %s.\n", __DATE__, __TIME__, OSTYPE);
479 #if defined(SETUID)
480 printf("\t* Gone was installed setuid to root.\n");
481 #endif /* SETUID */
482 #if defined(OSF1) && (EN_SEC)
483 printf("\t* Gone is OSF/1 Enhanced Security-aware.\n");
484 #endif /* OSF1 && EN_SEC */
485 printf("\t* Gone copyright MarcusCom 1998-2010.\n");
486 }
487
unlockVty()488 void unlockVty() {
489 #ifdef VT_LOCKSWITCH
490 if (vtylocked) {
491 int unlock = 0x2;
492 (void)ioctl(0, VT_LOCKSWITCH, &unlock);
493 }
494 #endif
495 }
496
497