source: trunk/third/tcp_wrappers/safe_finger.c @ 11717

Revision 11717, 5.0 KB checked in by danw, 26 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r11716, which included commits to RCS files with non-trunk default branches.
Line 
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
18static 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
30extern void exit();
31
32/* Local stuff */
33
34char    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
43int     finger_pid;
44
45void    cleanup(sig)
46int     sig;
47{
48    kill(finger_pid, SIGKILL);
49    exit(0);
50}
51
52main(argc, argv)
53int     argc;
54char  **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
138void    perror_exit(text)
139char   *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
147int     pipe_stdin(argv)
148char  **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}
Note: See TracBrowser for help on using the repository browser.