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
main
defined in line
52;
never used
Defined variables
path
defined in line
34; used 1 times
Defined macros