17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * safe_finger - finger client wrapper that protects against nasty stuff 37c478bd9Sstevel@tonic-gate * from finger servers. Use this program for automatic reverse finger 47c478bd9Sstevel@tonic-gate * probes, not the raw finger command. 57c478bd9Sstevel@tonic-gate * 67c478bd9Sstevel@tonic-gate * Build with: cc -o safe_finger safe_finger.c 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * The problem: some programs may react to stuff in the first column. Other 97c478bd9Sstevel@tonic-gate * programs may get upset by thrash anywhere on a line. File systems may 107c478bd9Sstevel@tonic-gate * fill up as the finger server keeps sending data. Text editors may bomb 117c478bd9Sstevel@tonic-gate * out on extremely long lines. The finger server may take forever because 127c478bd9Sstevel@tonic-gate * it is somehow wedged. The code below takes care of all this badness. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands. 157c478bd9Sstevel@tonic-gate */ 167c478bd9Sstevel@tonic-gate 177c478bd9Sstevel@tonic-gate #ifndef lint 187c478bd9Sstevel@tonic-gate static char sccsid[] = "@(#) safe_finger.c 1.4 94/12/28 17:42:41"; 197c478bd9Sstevel@tonic-gate #endif 207c478bd9Sstevel@tonic-gate 217c478bd9Sstevel@tonic-gate /* System libraries */ 227c478bd9Sstevel@tonic-gate 237c478bd9Sstevel@tonic-gate #include <sys/types.h> 247c478bd9Sstevel@tonic-gate #include <sys/stat.h> 257c478bd9Sstevel@tonic-gate #include <signal.h> 267c478bd9Sstevel@tonic-gate #include <stdio.h> 277c478bd9Sstevel@tonic-gate #include <ctype.h> 287c478bd9Sstevel@tonic-gate #include <pwd.h> 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate extern void exit(); 317c478bd9Sstevel@tonic-gate 327c478bd9Sstevel@tonic-gate /* Local stuff */ 337c478bd9Sstevel@tonic-gate 347c478bd9Sstevel@tonic-gate char path[] = "PATH=/bin:/usr/bin:/usr/ucb:/usr/bsd:/etc:/usr/etc:/usr/sbin"; 357c478bd9Sstevel@tonic-gate 367c478bd9Sstevel@tonic-gate #define TIME_LIMIT 60 /* Do not keep listinging forever */ 377c478bd9Sstevel@tonic-gate #define INPUT_LENGTH 100000 /* Do not keep listinging forever */ 387c478bd9Sstevel@tonic-gate #define LINE_LENGTH 128 /* Editors can choke on long lines */ 397c478bd9Sstevel@tonic-gate #define FINGER_PROGRAM "finger" /* Most, if not all, UNIX systems */ 407c478bd9Sstevel@tonic-gate #define UNPRIV_NAME "nobody" /* Preferred privilege level */ 417c478bd9Sstevel@tonic-gate #define UNPRIV_UGID 32767 /* Default uid and gid */ 427c478bd9Sstevel@tonic-gate 437c478bd9Sstevel@tonic-gate int finger_pid; 447c478bd9Sstevel@tonic-gate 457c478bd9Sstevel@tonic-gate void cleanup(sig) 467c478bd9Sstevel@tonic-gate int sig; 477c478bd9Sstevel@tonic-gate { 487c478bd9Sstevel@tonic-gate kill(finger_pid, SIGKILL); 497c478bd9Sstevel@tonic-gate exit(0); 507c478bd9Sstevel@tonic-gate } 517c478bd9Sstevel@tonic-gate 52*9455584cSIgor Kozhukhov int 537c478bd9Sstevel@tonic-gate main(argc, argv) 547c478bd9Sstevel@tonic-gate int argc; 557c478bd9Sstevel@tonic-gate char **argv; 567c478bd9Sstevel@tonic-gate { 577c478bd9Sstevel@tonic-gate int c; 587c478bd9Sstevel@tonic-gate int line_length = 0; 597c478bd9Sstevel@tonic-gate int finger_status; 607c478bd9Sstevel@tonic-gate int wait_pid; 617c478bd9Sstevel@tonic-gate int input_count = 0; 627c478bd9Sstevel@tonic-gate struct passwd *pwd; 637c478bd9Sstevel@tonic-gate 647c478bd9Sstevel@tonic-gate /* 657c478bd9Sstevel@tonic-gate * First of all, let's don't run with superuser privileges. 667c478bd9Sstevel@tonic-gate */ 677c478bd9Sstevel@tonic-gate if (getuid() == 0 || geteuid() == 0) { 687c478bd9Sstevel@tonic-gate if ((pwd = getpwnam(UNPRIV_NAME)) && pwd->pw_uid > 0) { 697c478bd9Sstevel@tonic-gate setgid(pwd->pw_gid); 707c478bd9Sstevel@tonic-gate setuid(pwd->pw_uid); 717c478bd9Sstevel@tonic-gate } else { 727c478bd9Sstevel@tonic-gate setgid(UNPRIV_UGID); 737c478bd9Sstevel@tonic-gate setuid(UNPRIV_UGID); 747c478bd9Sstevel@tonic-gate } 757c478bd9Sstevel@tonic-gate } 767c478bd9Sstevel@tonic-gate 777c478bd9Sstevel@tonic-gate /* 787c478bd9Sstevel@tonic-gate * Redirect our standard input through the raw finger command. 797c478bd9Sstevel@tonic-gate */ 807c478bd9Sstevel@tonic-gate if (putenv(path)) { 817c478bd9Sstevel@tonic-gate fprintf(stderr, "%s: putenv: out of memory", argv[0]); 827c478bd9Sstevel@tonic-gate exit(1); 837c478bd9Sstevel@tonic-gate } 847c478bd9Sstevel@tonic-gate argv[0] = FINGER_PROGRAM; 857c478bd9Sstevel@tonic-gate finger_pid = pipe_stdin(argv); 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate /* 887c478bd9Sstevel@tonic-gate * Don't wait forever (Peter Wemm <peter@gecko.DIALix.oz.au>). 897c478bd9Sstevel@tonic-gate */ 907c478bd9Sstevel@tonic-gate signal(SIGALRM, cleanup); 917c478bd9Sstevel@tonic-gate (void) alarm(TIME_LIMIT); 927c478bd9Sstevel@tonic-gate 937c478bd9Sstevel@tonic-gate /* 947c478bd9Sstevel@tonic-gate * Main filter loop. 957c478bd9Sstevel@tonic-gate */ 967c478bd9Sstevel@tonic-gate while ((c = getchar()) != EOF) { 977c478bd9Sstevel@tonic-gate if (input_count++ >= INPUT_LENGTH) { /* don't listen forever */ 987c478bd9Sstevel@tonic-gate fclose(stdin); 997c478bd9Sstevel@tonic-gate printf("\n\n Input truncated to %d bytes...\n", input_count - 1); 1007c478bd9Sstevel@tonic-gate break; 1017c478bd9Sstevel@tonic-gate } 1027c478bd9Sstevel@tonic-gate if (c == '\n') { /* good: end of line */ 1037c478bd9Sstevel@tonic-gate putchar(c); 1047c478bd9Sstevel@tonic-gate line_length = 0; 1057c478bd9Sstevel@tonic-gate } else { 1067c478bd9Sstevel@tonic-gate if (line_length >= LINE_LENGTH) { /* force end of line */ 1077c478bd9Sstevel@tonic-gate printf("\\\n"); 1087c478bd9Sstevel@tonic-gate line_length = 0; 1097c478bd9Sstevel@tonic-gate } 1107c478bd9Sstevel@tonic-gate if (line_length == 0) { /* protect left margin */ 1117c478bd9Sstevel@tonic-gate putchar(' '); 1127c478bd9Sstevel@tonic-gate line_length++; 1137c478bd9Sstevel@tonic-gate } 1147c478bd9Sstevel@tonic-gate if (isascii(c) && (isprint(c) || isspace(c))) { /* text */ 1157c478bd9Sstevel@tonic-gate if (c == '\\') { 1167c478bd9Sstevel@tonic-gate putchar(c); 1177c478bd9Sstevel@tonic-gate line_length++; 1187c478bd9Sstevel@tonic-gate } 1197c478bd9Sstevel@tonic-gate putchar(c); 1207c478bd9Sstevel@tonic-gate line_length++; 1217c478bd9Sstevel@tonic-gate } else { /* quote all other thash */ 1227c478bd9Sstevel@tonic-gate printf("\\%03o", c & 0377); 1237c478bd9Sstevel@tonic-gate line_length += 4; 1247c478bd9Sstevel@tonic-gate } 1257c478bd9Sstevel@tonic-gate } 1267c478bd9Sstevel@tonic-gate } 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate /* 1297c478bd9Sstevel@tonic-gate * Wait until the finger child process has terminated and account for its 1307c478bd9Sstevel@tonic-gate * exit status. Which will always be zero on most systems. 1317c478bd9Sstevel@tonic-gate */ 1327c478bd9Sstevel@tonic-gate while ((wait_pid = wait(&finger_status)) != -1 && wait_pid != finger_pid) 1337c478bd9Sstevel@tonic-gate /* void */ ; 1347c478bd9Sstevel@tonic-gate return (wait_pid != finger_pid || finger_status != 0); 1357c478bd9Sstevel@tonic-gate } 1367c478bd9Sstevel@tonic-gate 1377c478bd9Sstevel@tonic-gate /* perror_exit - report system error text and terminate */ 1387c478bd9Sstevel@tonic-gate 1397c478bd9Sstevel@tonic-gate void perror_exit(text) 1407c478bd9Sstevel@tonic-gate char *text; 1417c478bd9Sstevel@tonic-gate { 1427c478bd9Sstevel@tonic-gate perror(text); 1437c478bd9Sstevel@tonic-gate exit(1); 1447c478bd9Sstevel@tonic-gate } 1457c478bd9Sstevel@tonic-gate 1467c478bd9Sstevel@tonic-gate /* pipe_stdin - pipe stdin through program (from my ANSI to OLD C converter) */ 1477c478bd9Sstevel@tonic-gate 1487c478bd9Sstevel@tonic-gate int pipe_stdin(argv) 1497c478bd9Sstevel@tonic-gate char **argv; 1507c478bd9Sstevel@tonic-gate { 1517c478bd9Sstevel@tonic-gate int pipefds[2]; 1527c478bd9Sstevel@tonic-gate int pid; 1537c478bd9Sstevel@tonic-gate int i; 1547c478bd9Sstevel@tonic-gate struct stat st; 1557c478bd9Sstevel@tonic-gate 1567c478bd9Sstevel@tonic-gate /* 1577c478bd9Sstevel@tonic-gate * The code that sets up the pipe requires that file descriptors 0,1,2 1587c478bd9Sstevel@tonic-gate * are already open. All kinds of mysterious things will happen if that 1597c478bd9Sstevel@tonic-gate * is not the case. The following loops makes sure that descriptors 0,1,2 1607c478bd9Sstevel@tonic-gate * are set up properly. 1617c478bd9Sstevel@tonic-gate */ 1627c478bd9Sstevel@tonic-gate 1637c478bd9Sstevel@tonic-gate for (i = 0; i < 3; i++) { 1647c478bd9Sstevel@tonic-gate if (fstat(i, &st) == -1 && open("/dev/null", 2) != i) 1657c478bd9Sstevel@tonic-gate perror_exit("open /dev/null"); 1667c478bd9Sstevel@tonic-gate } 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate /* 1697c478bd9Sstevel@tonic-gate * Set up the pipe that interposes the command into our standard input 1707c478bd9Sstevel@tonic-gate * stream. 1717c478bd9Sstevel@tonic-gate */ 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate if (pipe(pipefds)) 1747c478bd9Sstevel@tonic-gate perror_exit("pipe"); 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate switch (pid = fork()) { 1777c478bd9Sstevel@tonic-gate case -1: /* error */ 1787c478bd9Sstevel@tonic-gate perror_exit("fork"); 1797c478bd9Sstevel@tonic-gate /* NOTREACHED */ 1807c478bd9Sstevel@tonic-gate case 0: /* child */ 1817c478bd9Sstevel@tonic-gate (void) close(pipefds[0]); /* close reading end */ 1827c478bd9Sstevel@tonic-gate (void) close(1); /* connect stdout to pipe */ 1837c478bd9Sstevel@tonic-gate if (dup(pipefds[1]) != 1) 1847c478bd9Sstevel@tonic-gate perror_exit("dup"); 1857c478bd9Sstevel@tonic-gate (void) close(pipefds[1]); /* close redundant fd */ 1867c478bd9Sstevel@tonic-gate (void) execvp(argv[0], argv); 1877c478bd9Sstevel@tonic-gate perror_exit(argv[0]); 1887c478bd9Sstevel@tonic-gate /* NOTREACHED */ 1897c478bd9Sstevel@tonic-gate default: /* parent */ 1907c478bd9Sstevel@tonic-gate (void) close(pipefds[1]); /* close writing end */ 1917c478bd9Sstevel@tonic-gate (void) close(0); /* connect stdin to pipe */ 1927c478bd9Sstevel@tonic-gate if (dup(pipefds[0]) != 0) 1937c478bd9Sstevel@tonic-gate perror_exit("dup"); 1947c478bd9Sstevel@tonic-gate (void) close(pipefds[0]); /* close redundant fd */ 1957c478bd9Sstevel@tonic-gate return (pid); 1967c478bd9Sstevel@tonic-gate } 1977c478bd9Sstevel@tonic-gate } 198