xref: /freebsd/contrib/tcp_wrappers/safe_finger.c (revision 14f102eacc8434a5a1f96466752578a4167140c9)
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