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.
6 * Build with: cc -o safe_finger safe_finger.c
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.
14 * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
17 /* System libraries */
19 #include <sys/types.h>
31 char path
[] = "PATH=/bin:/usr/bin:/usr/ucb:/usr/bsd:/etc:/usr/etc:/usr/sbin";
33 #define TIME_LIMIT 60 /* Do not keep listinging forever */
34 #define INPUT_LENGTH 100000 /* Do not keep listinging forever */
35 #define LINE_LENGTH 128 /* Editors can choke on long lines */
36 #define FINGER_PROGRAM "finger" /* Most, if not all, UNIX systems */
37 #define UNPRIV_NAME "nobody" /* Preferred privilege level */
38 #define UNPRIV_UGID 32767 /* Default uid and gid */
40 void perror_exit(char *text
) __NORETURN
;
46 kill(finger_pid
, SIGKILL
);
63 * First of all, let's don't run with superuser privileges.
65 if (getuid() == 0 || geteuid() == 0) {
66 if ((pwd
= getpwnam(UNPRIV_NAME
)) && pwd
->pw_uid
> 0) {
76 * Redirect our standard input through the raw finger command.
79 fprintf(stderr
, "%s: putenv: out of memory", argv
[0]);
82 argv
[0] = FINGER_PROGRAM
;
83 finger_pid
= pipe_stdin(argv
);
86 * Don't wait forever (Peter Wemm <peter@gecko.DIALix.oz.au>).
88 signal(SIGALRM
, cleanup
);
89 (void) alarm(TIME_LIMIT
);
94 while ((c
= getchar()) != EOF
) {
95 if (input_count
++ >= INPUT_LENGTH
) { /* don't listen forever */
97 printf("\n\n Input truncated to %d bytes...\n", input_count
- 1);
100 if (c
== '\n') { /* good: end of line */
104 if (line_length
>= LINE_LENGTH
) { /* force end of line */
108 if (line_length
== 0) { /* protect left margin */
112 if (isascii(c
) && (isprint(c
) || isspace(c
))) { /* text */
119 } else { /* quote all other thash */
120 printf("\\%03o", c
& 0377);
127 * Wait until the finger child process has terminated and account for its
128 * exit status. Which will always be zero on most systems.
130 while ((wait_pid
= wait(&finger_status
)) != -1 && wait_pid
!= finger_pid
)
132 return (wait_pid
!= finger_pid
|| finger_status
!= 0);
135 /* perror_exit - report system error text and terminate */
138 perror_exit(char *text
)
144 /* pipe_stdin - pipe stdin through program (from my ANSI to OLD C converter) */
155 * The code that sets up the pipe requires that file descriptors 0,1,2
156 * are already open. All kinds of mysterious things will happen if that
157 * is not the case. The following loops makes sure that descriptors 0,1,2
158 * are set up properly.
161 for (i
= 0; i
< 3; i
++) {
162 if (fstat(i
, &st
) == -1 && open("/dev/null", 2) != i
)
163 perror_exit("open /dev/null");
167 * Set up the pipe that interposes the command into our standard input
174 switch (pid
= fork()) {
179 (void) close(pipefds
[0]); /* close reading end */
180 (void) close(1); /* connect stdout to pipe */
181 if (dup(pipefds
[1]) != 1)
183 (void) close(pipefds
[1]); /* close redundant fd */
184 (void) execvp(argv
[0], argv
);
185 perror_exit(argv
[0]);
187 default: /* parent */
188 (void) close(pipefds
[1]); /* close writing end */
189 (void) close(0); /* connect stdin to pipe */
190 if (dup(pipefds
[0]) != 0)
192 (void) close(pipefds
[0]); /* close redundant fd */