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