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
cleanup(sig)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
main(int argc,char ** argv)52*14f102eaSEd Maste main(int argc, char **argv)
532aef6930SMark Murray {
542aef6930SMark Murray int c;
552aef6930SMark Murray int line_length = 0;
562aef6930SMark Murray int finger_status;
572aef6930SMark Murray int wait_pid;
582aef6930SMark Murray int input_count = 0;
592aef6930SMark Murray struct passwd *pwd;
602aef6930SMark Murray
612aef6930SMark Murray /*
622aef6930SMark Murray * First of all, let's don't run with superuser privileges.
632aef6930SMark Murray */
642aef6930SMark Murray if (getuid() == 0 || geteuid() == 0) {
652aef6930SMark Murray if ((pwd = getpwnam(UNPRIV_NAME)) && pwd->pw_uid > 0) {
662aef6930SMark Murray setgid(pwd->pw_gid);
672aef6930SMark Murray setuid(pwd->pw_uid);
682aef6930SMark Murray } else {
692aef6930SMark Murray setgid(UNPRIV_UGID);
702aef6930SMark Murray setuid(UNPRIV_UGID);
712aef6930SMark Murray }
722aef6930SMark Murray }
732aef6930SMark Murray
742aef6930SMark Murray /*
752aef6930SMark Murray * Redirect our standard input through the raw finger command.
762aef6930SMark Murray */
772aef6930SMark Murray if (putenv(path)) {
782aef6930SMark Murray fprintf(stderr, "%s: putenv: out of memory", argv[0]);
792aef6930SMark Murray exit(1);
802aef6930SMark Murray }
812aef6930SMark Murray argv[0] = FINGER_PROGRAM;
822aef6930SMark Murray finger_pid = pipe_stdin(argv);
832aef6930SMark Murray
842aef6930SMark Murray /*
852aef6930SMark Murray * Don't wait forever (Peter Wemm <peter@gecko.DIALix.oz.au>).
862aef6930SMark Murray */
872aef6930SMark Murray signal(SIGALRM, cleanup);
882aef6930SMark Murray (void) alarm(TIME_LIMIT);
892aef6930SMark Murray
902aef6930SMark Murray /*
912aef6930SMark Murray * Main filter loop.
922aef6930SMark Murray */
932aef6930SMark Murray while ((c = getchar()) != EOF) {
942aef6930SMark Murray if (input_count++ >= INPUT_LENGTH) { /* don't listen forever */
952aef6930SMark Murray fclose(stdin);
962aef6930SMark Murray printf("\n\n Input truncated to %d bytes...\n", input_count - 1);
972aef6930SMark Murray break;
982aef6930SMark Murray }
992aef6930SMark Murray if (c == '\n') { /* good: end of line */
1002aef6930SMark Murray putchar(c);
1012aef6930SMark Murray line_length = 0;
1022aef6930SMark Murray } else {
1032aef6930SMark Murray if (line_length >= LINE_LENGTH) { /* force end of line */
1042aef6930SMark Murray printf("\\\n");
1052aef6930SMark Murray line_length = 0;
1062aef6930SMark Murray }
1072aef6930SMark Murray if (line_length == 0) { /* protect left margin */
1082aef6930SMark Murray putchar(' ');
1092aef6930SMark Murray line_length++;
1102aef6930SMark Murray }
1112aef6930SMark Murray if (isascii(c) && (isprint(c) || isspace(c))) { /* text */
1122aef6930SMark Murray if (c == '\\') {
1132aef6930SMark Murray putchar(c);
1142aef6930SMark Murray line_length++;
1152aef6930SMark Murray }
1162aef6930SMark Murray putchar(c);
1172aef6930SMark Murray line_length++;
1182aef6930SMark Murray } else { /* quote all other thash */
1192aef6930SMark Murray printf("\\%03o", c & 0377);
1202aef6930SMark Murray line_length += 4;
1212aef6930SMark Murray }
1222aef6930SMark Murray }
1232aef6930SMark Murray }
1242aef6930SMark Murray
1252aef6930SMark Murray /*
1262aef6930SMark Murray * Wait until the finger child process has terminated and account for its
1272aef6930SMark Murray * exit status. Which will always be zero on most systems.
1282aef6930SMark Murray */
1292aef6930SMark Murray while ((wait_pid = wait(&finger_status)) != -1 && wait_pid != finger_pid)
1302aef6930SMark Murray /* void */ ;
1312aef6930SMark Murray return (wait_pid != finger_pid || finger_status != 0);
1322aef6930SMark Murray }
1332aef6930SMark Murray
1342aef6930SMark Murray /* perror_exit - report system error text and terminate */
1352aef6930SMark Murray
perror_exit(char * text)136*14f102eaSEd Maste void perror_exit(char *text)
1372aef6930SMark Murray {
1382aef6930SMark Murray perror(text);
1392aef6930SMark Murray exit(1);
1402aef6930SMark Murray }
1412aef6930SMark Murray
1422aef6930SMark Murray /* pipe_stdin - pipe stdin through program (from my ANSI to OLD C converter) */
1432aef6930SMark Murray
pipe_stdin(char ** argv)144*14f102eaSEd Maste int pipe_stdin(char **argv)
1452aef6930SMark Murray {
1462aef6930SMark Murray int pipefds[2];
1472aef6930SMark Murray int pid;
1482aef6930SMark Murray int i;
1492aef6930SMark Murray struct stat st;
1502aef6930SMark Murray
1512aef6930SMark Murray /*
1522aef6930SMark Murray * The code that sets up the pipe requires that file descriptors 0,1,2
1532aef6930SMark Murray * are already open. All kinds of mysterious things will happen if that
1542aef6930SMark Murray * is not the case. The following loops makes sure that descriptors 0,1,2
1552aef6930SMark Murray * are set up properly.
1562aef6930SMark Murray */
1572aef6930SMark Murray
1582aef6930SMark Murray for (i = 0; i < 3; i++) {
1592aef6930SMark Murray if (fstat(i, &st) == -1 && open("/dev/null", 2) != i)
1602aef6930SMark Murray perror_exit("open /dev/null");
1612aef6930SMark Murray }
1622aef6930SMark Murray
1632aef6930SMark Murray /*
1642aef6930SMark Murray * Set up the pipe that interposes the command into our standard input
1652aef6930SMark Murray * stream.
1662aef6930SMark Murray */
1672aef6930SMark Murray
1682aef6930SMark Murray if (pipe(pipefds))
1692aef6930SMark Murray perror_exit("pipe");
1702aef6930SMark Murray
1712aef6930SMark Murray switch (pid = fork()) {
1722aef6930SMark Murray case -1: /* error */
1732aef6930SMark Murray perror_exit("fork");
1742aef6930SMark Murray /* NOTREACHED */
1752aef6930SMark Murray case 0: /* child */
1762aef6930SMark Murray (void) close(pipefds[0]); /* close reading end */
1772aef6930SMark Murray (void) close(1); /* connect stdout to pipe */
1782aef6930SMark Murray if (dup(pipefds[1]) != 1)
1792aef6930SMark Murray perror_exit("dup");
1802aef6930SMark Murray (void) close(pipefds[1]); /* close redundant fd */
1812aef6930SMark Murray (void) execvp(argv[0], argv);
1822aef6930SMark Murray perror_exit(argv[0]);
1832aef6930SMark Murray /* NOTREACHED */
1842aef6930SMark Murray default: /* parent */
1852aef6930SMark Murray (void) close(pipefds[1]); /* close writing end */
1862aef6930SMark Murray (void) close(0); /* connect stdin to pipe */
1872aef6930SMark Murray if (dup(pipefds[0]) != 0)
1882aef6930SMark Murray perror_exit("dup");
1892aef6930SMark Murray (void) close(pipefds[0]); /* close redundant fd */
1902aef6930SMark Murray return (pid);
1912aef6930SMark Murray }
1922aef6930SMark Murray }
193