12aef6930SMark Murray /* 22aef6930SMark Murray * safe_finger - finger client wrapper that protects against nasty stuff 32aef6930SMark Murray * from finger servers. Use this program for automatic reverse finger 42aef6930SMark Murray * probes, not the raw finger command. 52aef6930SMark Murray * 62aef6930SMark Murray * Build with: cc -o safe_finger safe_finger.c 72aef6930SMark Murray * 82aef6930SMark Murray * The problem: some programs may react to stuff in the first column. Other 92aef6930SMark Murray * programs may get upset by thrash anywhere on a line. File systems may 102aef6930SMark Murray * fill up as the finger server keeps sending data. Text editors may bomb 112aef6930SMark Murray * out on extremely long lines. The finger server may take forever because 122aef6930SMark Murray * it is somehow wedged. The code below takes care of all this badness. 132aef6930SMark Murray * 142aef6930SMark Murray * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands. 152aef6930SMark Murray */ 162aef6930SMark Murray 172aef6930SMark Murray #ifndef lint 182aef6930SMark Murray static char sccsid[] = "@(#) safe_finger.c 1.4 94/12/28 17:42:41"; 192aef6930SMark Murray #endif 202aef6930SMark Murray 212aef6930SMark Murray /* System libraries */ 222aef6930SMark Murray 232aef6930SMark Murray #include <sys/types.h> 242aef6930SMark Murray #include <sys/stat.h> 252aef6930SMark Murray #include <signal.h> 262aef6930SMark Murray #include <stdio.h> 272aef6930SMark Murray #include <ctype.h> 282aef6930SMark Murray #include <pwd.h> 292aef6930SMark Murray 302aef6930SMark Murray extern void exit(); 312aef6930SMark Murray 322aef6930SMark Murray /* Local stuff */ 332aef6930SMark Murray 342aef6930SMark Murray char path[] = "PATH=/bin:/usr/bin:/usr/ucb:/usr/bsd:/etc:/usr/etc:/usr/sbin"; 352aef6930SMark Murray 362aef6930SMark Murray #define TIME_LIMIT 60 /* Do not keep listinging forever */ 372aef6930SMark Murray #define INPUT_LENGTH 100000 /* Do not keep listinging forever */ 382aef6930SMark Murray #define LINE_LENGTH 128 /* Editors can choke on long lines */ 392aef6930SMark Murray #define FINGER_PROGRAM "finger" /* Most, if not all, UNIX systems */ 402aef6930SMark Murray #define UNPRIV_NAME "nobody" /* Preferred privilege level */ 412aef6930SMark Murray #define UNPRIV_UGID 32767 /* Default uid and gid */ 422aef6930SMark Murray 432aef6930SMark Murray int finger_pid; 442aef6930SMark Murray 452aef6930SMark Murray void cleanup(sig) 462aef6930SMark Murray int sig; 472aef6930SMark Murray { 482aef6930SMark Murray kill(finger_pid, SIGKILL); 492aef6930SMark Murray exit(0); 502aef6930SMark Murray } 512aef6930SMark Murray 522aef6930SMark Murray main(argc, argv) 532aef6930SMark Murray int argc; 542aef6930SMark Murray char **argv; 552aef6930SMark Murray { 562aef6930SMark Murray int c; 572aef6930SMark Murray int line_length = 0; 582aef6930SMark Murray int finger_status; 592aef6930SMark Murray int wait_pid; 602aef6930SMark Murray int input_count = 0; 612aef6930SMark Murray struct passwd *pwd; 622aef6930SMark Murray 632aef6930SMark Murray /* 642aef6930SMark Murray * First of all, let's don't run with superuser privileges. 652aef6930SMark Murray */ 662aef6930SMark Murray if (getuid() == 0 || geteuid() == 0) { 672aef6930SMark Murray if ((pwd = getpwnam(UNPRIV_NAME)) && pwd->pw_uid > 0) { 682aef6930SMark Murray setgid(pwd->pw_gid); 692aef6930SMark Murray setuid(pwd->pw_uid); 702aef6930SMark Murray } else { 712aef6930SMark Murray setgid(UNPRIV_UGID); 722aef6930SMark Murray setuid(UNPRIV_UGID); 732aef6930SMark Murray } 742aef6930SMark Murray } 752aef6930SMark Murray 762aef6930SMark Murray /* 772aef6930SMark Murray * Redirect our standard input through the raw finger command. 782aef6930SMark Murray */ 792aef6930SMark Murray if (putenv(path)) { 802aef6930SMark Murray fprintf(stderr, "%s: putenv: out of memory", argv[0]); 812aef6930SMark Murray exit(1); 822aef6930SMark Murray } 832aef6930SMark Murray argv[0] = FINGER_PROGRAM; 842aef6930SMark Murray finger_pid = pipe_stdin(argv); 852aef6930SMark Murray 862aef6930SMark Murray /* 872aef6930SMark Murray * Don't wait forever (Peter Wemm <peter@gecko.DIALix.oz.au>). 882aef6930SMark Murray */ 892aef6930SMark Murray signal(SIGALRM, cleanup); 902aef6930SMark Murray (void) alarm(TIME_LIMIT); 912aef6930SMark Murray 922aef6930SMark Murray /* 932aef6930SMark Murray * Main filter loop. 942aef6930SMark Murray */ 952aef6930SMark Murray while ((c = getchar()) != EOF) { 962aef6930SMark Murray if (input_count++ >= INPUT_LENGTH) { /* don't listen forever */ 972aef6930SMark Murray fclose(stdin); 982aef6930SMark Murray printf("\n\n Input truncated to %d bytes...\n", input_count - 1); 992aef6930SMark Murray break; 1002aef6930SMark Murray } 1012aef6930SMark Murray if (c == '\n') { /* good: end of line */ 1022aef6930SMark Murray putchar(c); 1032aef6930SMark Murray line_length = 0; 1042aef6930SMark Murray } else { 1052aef6930SMark Murray if (line_length >= LINE_LENGTH) { /* force end of line */ 1062aef6930SMark Murray printf("\\\n"); 1072aef6930SMark Murray line_length = 0; 1082aef6930SMark Murray } 1092aef6930SMark Murray if (line_length == 0) { /* protect left margin */ 1102aef6930SMark Murray putchar(' '); 1112aef6930SMark Murray line_length++; 1122aef6930SMark Murray } 1132aef6930SMark Murray if (isascii(c) && (isprint(c) || isspace(c))) { /* text */ 1142aef6930SMark Murray if (c == '\\') { 1152aef6930SMark Murray putchar(c); 1162aef6930SMark Murray line_length++; 1172aef6930SMark Murray } 1182aef6930SMark Murray putchar(c); 1192aef6930SMark Murray line_length++; 1202aef6930SMark Murray } else { /* quote all other thash */ 1212aef6930SMark Murray printf("\\%03o", c & 0377); 1222aef6930SMark Murray line_length += 4; 1232aef6930SMark Murray } 1242aef6930SMark Murray } 1252aef6930SMark Murray } 1262aef6930SMark Murray 1272aef6930SMark Murray /* 1282aef6930SMark Murray * Wait until the finger child process has terminated and account for its 1292aef6930SMark Murray * exit status. Which will always be zero on most systems. 1302aef6930SMark Murray */ 1312aef6930SMark Murray while ((wait_pid = wait(&finger_status)) != -1 && wait_pid != finger_pid) 1322aef6930SMark Murray /* void */ ; 1332aef6930SMark Murray return (wait_pid != finger_pid || finger_status != 0); 1342aef6930SMark Murray } 1352aef6930SMark Murray 1362aef6930SMark Murray /* perror_exit - report system error text and terminate */ 1372aef6930SMark Murray 1382aef6930SMark Murray void perror_exit(text) 1392aef6930SMark Murray char *text; 1402aef6930SMark Murray { 1412aef6930SMark Murray perror(text); 1422aef6930SMark Murray exit(1); 1432aef6930SMark Murray } 1442aef6930SMark Murray 1452aef6930SMark Murray /* pipe_stdin - pipe stdin through program (from my ANSI to OLD C converter) */ 1462aef6930SMark Murray 1472aef6930SMark Murray int pipe_stdin(argv) 1482aef6930SMark Murray char **argv; 1492aef6930SMark Murray { 1502aef6930SMark Murray int pipefds[2]; 1512aef6930SMark Murray int pid; 1522aef6930SMark Murray int i; 1532aef6930SMark Murray struct stat st; 1542aef6930SMark Murray 1552aef6930SMark Murray /* 1562aef6930SMark Murray * The code that sets up the pipe requires that file descriptors 0,1,2 1572aef6930SMark Murray * are already open. All kinds of mysterious things will happen if that 1582aef6930SMark Murray * is not the case. The following loops makes sure that descriptors 0,1,2 1592aef6930SMark Murray * are set up properly. 1602aef6930SMark Murray */ 1612aef6930SMark Murray 1622aef6930SMark Murray for (i = 0; i < 3; i++) { 1632aef6930SMark Murray if (fstat(i, &st) == -1 && open("/dev/null", 2) != i) 1642aef6930SMark Murray perror_exit("open /dev/null"); 1652aef6930SMark Murray } 1662aef6930SMark Murray 1672aef6930SMark Murray /* 1682aef6930SMark Murray * Set up the pipe that interposes the command into our standard input 1692aef6930SMark Murray * stream. 1702aef6930SMark Murray */ 1712aef6930SMark Murray 1722aef6930SMark Murray if (pipe(pipefds)) 1732aef6930SMark Murray perror_exit("pipe"); 1742aef6930SMark Murray 1752aef6930SMark Murray switch (pid = fork()) { 1762aef6930SMark Murray case -1: /* error */ 1772aef6930SMark Murray perror_exit("fork"); 1782aef6930SMark Murray /* NOTREACHED */ 1792aef6930SMark Murray case 0: /* child */ 1802aef6930SMark Murray (void) close(pipefds[0]); /* close reading end */ 1812aef6930SMark Murray (void) close(1); /* connect stdout to pipe */ 1822aef6930SMark Murray if (dup(pipefds[1]) != 1) 1832aef6930SMark Murray perror_exit("dup"); 1842aef6930SMark Murray (void) close(pipefds[1]); /* close redundant fd */ 1852aef6930SMark Murray (void) execvp(argv[0], argv); 1862aef6930SMark Murray perror_exit(argv[0]); 1872aef6930SMark Murray /* NOTREACHED */ 1882aef6930SMark Murray default: /* parent */ 1892aef6930SMark Murray (void) close(pipefds[1]); /* close writing end */ 1902aef6930SMark Murray (void) close(0); /* connect stdin to pipe */ 1912aef6930SMark Murray if (dup(pipefds[0]) != 0) 1922aef6930SMark Murray perror_exit("dup"); 1932aef6930SMark Murray (void) close(pipefds[0]); /* close redundant fd */ 1942aef6930SMark Murray return (pid); 1952aef6930SMark Murray } 1962aef6930SMark Murray } 197