home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / pc / SATAN11.ZIP / SRC / MISC / SAFE_FIN.C < prev    next >
Encoding:
C/C++ Source or Header  |  1995-03-20  |  5.2 KB  |  197 lines

  1.  /*
  2.   * safe_finger - finger client wrapper that protects against nasty stuff
  3.   * from finger servers. Use this program for automatic reverse finger
  4.   * probes, not the raw finger command.
  5.   * 
  6.   * Build with: cc -o safe_finger safe_finger.c
  7.   * 
  8.   * The problem: some programs may react to stuff in the first column. Other
  9.   * programs may get upset by thrash anywhere on a line. File systems may
  10.   * fill up as the finger server keeps sending data. Text editors may bomb
  11.   * out on extremely long lines. The finger server may take forever because
  12.   * it is somehow wedged. The code below takes care of all this badness.
  13.   * 
  14.   * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
  15.   */
  16.  
  17. #ifndef lint
  18. static char sccsid[] = "@(#) safe_finger.c 1.4 94/12/28 17:42:41";
  19. #endif
  20.  
  21. /* System libraries */
  22.  
  23. #include <sys/types.h>
  24. #include <sys/stat.h>
  25. #include <signal.h>
  26. #include <stdio.h>
  27. #include <ctype.h>
  28. #include <pwd.h>
  29.  
  30. extern void exit();
  31.  
  32. /* Local stuff */
  33.  
  34. char    path[] = "PATH=/bin:/usr/bin:/usr/ucb:/usr/bsd:/etc:/usr/etc:/usr/sbin";
  35.  
  36. #define    TIME_LIMIT    60        /* Do not keep listinging forever */
  37. #define    INPUT_LENGTH    100000        /* Do not keep listinging forever */
  38. #define    LINE_LENGTH    128        /* Editors can choke on long lines */
  39. #define    FINGER_PROGRAM    "finger"    /* Most, if not all, UNIX systems */
  40. #define    UNPRIV_NAME    "nobody"    /* Preferred privilege level */
  41. #define    UNPRIV_UGID    32767        /* Default uid and gid */
  42.  
  43. int     finger_pid;
  44.  
  45. void    cleanup(sig)
  46. int     sig;
  47. {
  48.     kill(finger_pid, SIGKILL);
  49.     exit(0);
  50. }
  51.  
  52. main(argc, argv)
  53. int     argc;
  54. char  **argv;
  55. {
  56.     int     c;
  57.     int     line_length = 0;
  58.     int     finger_status;
  59.     int     wait_pid;
  60.     int     input_count = 0;
  61.     struct passwd *pwd;
  62.  
  63.     /*
  64.      * First of all, let's don't run with superuser privileges.
  65.      */
  66.     if (getuid() == 0 || geteuid() == 0) {
  67.     if ((pwd = getpwnam(UNPRIV_NAME)) && pwd->pw_uid > 0) {
  68.         setgid(pwd->pw_gid);
  69.         setuid(pwd->pw_uid);
  70.     } else {
  71.         setgid(UNPRIV_UGID);
  72.         setuid(UNPRIV_UGID);
  73.     }
  74.     }
  75.  
  76.     /*
  77.      * Redirect our standard input through the raw finger command.
  78.      */
  79.     if (putenv(path)) {
  80.     fprintf(stderr, "%s: putenv: out of memory", argv[0]);
  81.     exit(1);
  82.     }
  83.     argv[0] = FINGER_PROGRAM;
  84.     finger_pid = pipe_stdin(argv);
  85.  
  86.     /*
  87.      * Don't wait forever (Peter Wemm <peter@gecko.DIALix.oz.au>).
  88.      */
  89.     signal(SIGALRM, cleanup);
  90.     (void) alarm(TIME_LIMIT);
  91.  
  92.     /*
  93.      * Main filter loop.
  94.      */
  95.     while ((c = getchar()) != EOF) {
  96.     if (input_count++ >= INPUT_LENGTH) {    /* don't listen forever */
  97.         fclose(stdin);
  98.         printf("\n\n Input truncated to %d bytes...\n", input_count - 1);
  99.         break;
  100.     }
  101.     if (c == '\n') {            /* good: end of line */
  102.         putchar(c);
  103.         line_length = 0;
  104.     } else {
  105.         if (line_length >= LINE_LENGTH) {    /* force end of line */
  106.         printf("\\\n");
  107.         line_length = 0;
  108.         }
  109.         if (line_length == 0) {        /* protect left margin */
  110.         putchar(' ');
  111.         line_length++;
  112.         }
  113.         if (isascii(c) && (isprint(c) || isspace(c))) {    /* text */
  114.         if (c == '\\') {
  115.             putchar(c);
  116.             line_length++;
  117.         }
  118.         putchar(c);
  119.         line_length++;
  120.         } else {                /* quote all other thash */
  121.         printf("\\%03o", c & 0377);
  122.         line_length += 4;
  123.         }
  124.     }
  125.     }
  126.  
  127.     /*
  128.      * Wait until the finger child process has terminated and account for its
  129.      * exit status. Which will always be zero on most systems.
  130.      */
  131.     while ((wait_pid = wait(&finger_status)) != -1 && wait_pid != finger_pid)
  132.      /* void */ ;
  133.     return (wait_pid != finger_pid || finger_status != 0);
  134. }
  135.  
  136. /* perror_exit - report system error text and terminate */
  137.  
  138. void    perror_exit(text)
  139. char   *text;
  140. {
  141.     perror(text);
  142.     exit(1);
  143. }
  144.  
  145. /* pipe_stdin - pipe stdin through program (from my ANSI to OLD C converter) */
  146.  
  147. int     pipe_stdin(argv)
  148. char  **argv;
  149. {
  150.     int     pipefds[2];
  151.     int     pid;
  152.     int     i;
  153.     struct stat st;
  154.  
  155.     /*
  156.      * The code that sets up the pipe requires that file descriptors 0,1,2
  157.      * are already open. All kinds of mysterious things will happen if that
  158.      * is not the case. The following loops makes sure that descriptors 0,1,2
  159.      * are set up properly.
  160.      */
  161.  
  162.     for (i = 0; i < 3; i++) {
  163.     if (fstat(i, &st) == -1 && open("/dev/null", 2) != i)
  164.         perror_exit("open /dev/null");
  165.     }
  166.  
  167.     /*
  168.      * Set up the pipe that interposes the command into our standard input
  169.      * stream.
  170.      */
  171.  
  172.     if (pipe(pipefds))
  173.     perror_exit("pipe");
  174.  
  175.     switch (pid = fork()) {
  176.     case -1:                    /* error */
  177.     perror_exit("fork");
  178.     /* NOTREACHED */
  179.     case 0:                    /* child */
  180.     (void) close(pipefds[0]);        /* close reading end */
  181.     (void) close(1);            /* connect stdout to pipe */
  182.     if (dup(pipefds[1]) != 1)
  183.         perror_exit("dup");
  184.     (void) close(pipefds[1]);        /* close redundant fd */
  185.     (void) execvp(argv[0], argv);
  186.     perror_exit(argv[0]);
  187.     /* NOTREACHED */
  188.     default:                    /* parent */
  189.     (void) close(pipefds[1]);        /* close writing end */
  190.     (void) close(0);            /* connect stdin to pipe */
  191.     if (dup(pipefds[0]) != 0)
  192.         perror_exit("dup");
  193.     (void) close(pipefds[0]);        /* close redundant fd */
  194.     return (pid);
  195.     }
  196. }
  197.