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: }

Defined functions

cleanup defined in line 45; used 1 times
  • in line 89
main defined in line 52; never used
perror_exit defined in line 138; used 6 times
pipe_stdin defined in line 147; used 1 times
  • in line 84

Defined variables

finger_pid defined in line 43; used 4 times
path defined in line 34; used 1 times
  • in line 79
sccsid defined in line 18; never used

Defined macros

FINGER_PROGRAM defined in line 39; used 1 times
  • in line 83
INPUT_LENGTH defined in line 37; used 1 times
  • in line 96
LINE_LENGTH defined in line 38; used 1 times
TIME_LIMIT defined in line 36; used 1 times
  • in line 90
UNPRIV_NAME defined in line 40; used 1 times
  • in line 67
UNPRIV_UGID defined in line 41; used 2 times
Last modified: 1994-12-28
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3024
Valid CSS Valid XHTML 1.0 Strict