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

Revision 11717, 7.9 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  * Routines to parse an inetd.conf or tlid.conf file. This would be a great
3  * job for a PERL script.
4  *
5  * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
6  */
7
8#ifndef lint
9static char sccsid[] = "@(#) inetcf.c 1.7 97/02/12 02:13:23";
10#endif
11
12#include <sys/types.h>
13#include <sys/stat.h>
14#include <stdio.h>
15#include <errno.h>
16#include <string.h>
17
18extern int errno;
19extern void exit();
20
21#include "tcpd.h"
22#include "inetcf.h"
23
24 /*
25  * Network configuration files may live in unusual places. Here are some
26  * guesses. Shorter names follow longer ones.
27  */
28char   *inet_files[] = {
29    "/private/etc/inetd.conf",          /* NEXT */
30    "/etc/inet/inetd.conf",             /* SYSV4 */
31    "/usr/etc/inetd.conf",              /* IRIX?? */
32    "/etc/inetd.conf",                  /* BSD */
33    "/etc/net/tlid.conf",               /* SYSV4?? */
34    "/etc/saf/tlid.conf",               /* SYSV4?? */
35    "/etc/tlid.conf",                   /* SYSV4?? */
36    0,
37};
38
39static void inet_chk();
40static char *base_name();
41
42 /*
43  * Structure with everything we know about a service.
44  */
45struct inet_ent {
46    struct inet_ent *next;
47    int     type;
48    char    name[1];
49};
50
51static struct inet_ent *inet_list = 0;
52
53static char whitespace[] = " \t\r\n";
54
55/* inet_conf - read in and examine inetd.conf (or tlid.conf) entries */
56
57char   *inet_cfg(conf)
58char   *conf;
59{
60    char    buf[BUFSIZ];
61    FILE   *fp;
62    char   *service;
63    char   *protocol;
64    char   *user;
65    char   *path;
66    char   *arg0;
67    char   *arg1;
68    struct tcpd_context saved_context;
69    char   *percent_m();
70    int     i;
71    struct stat st;
72
73    saved_context = tcpd_context;
74
75    /*
76     * The inetd.conf (or tlid.conf) information is so useful that we insist
77     * on its availability. When no file is given run a series of educated
78     * guesses.
79     */
80    if (conf != 0) {
81        if ((fp = fopen(conf, "r")) == 0) {
82            fprintf(stderr, percent_m(buf, "open %s: %m\n"), conf);
83            exit(1);
84        }
85    } else {
86        for (i = 0; inet_files[i] && (fp = fopen(inet_files[i], "r")) == 0; i++)
87             /* void */ ;
88        if (fp == 0) {
89            fprintf(stderr, "Cannot find your inetd.conf or tlid.conf file.\n");
90            fprintf(stderr, "Please specify its location.\n");
91            exit(1);
92        }
93        conf = inet_files[i];
94        check_path(conf, &st);
95    }
96
97    /*
98     * Process the file. After the 7.0 wrapper release it became clear that
99     * there are many more inetd.conf formats than the 8 systems that I had
100     * studied. EP/IX uses a two-line specification for rpc services; HP-UX
101     * permits long lines to be broken with backslash-newline.
102     */
103    tcpd_context.file = conf;
104    tcpd_context.line = 0;
105    while (xgets(buf, sizeof(buf), fp)) {
106        service = strtok(buf, whitespace);      /* service */
107        if (service == 0 || *service == '#')
108            continue;
109        if (STR_NE(service, "stream") && STR_NE(service, "dgram"))
110            strtok((char *) 0, whitespace);     /* endpoint */
111        protocol = strtok((char *) 0, whitespace);
112        (void) strtok((char *) 0, whitespace);  /* wait */
113        if ((user = strtok((char *) 0, whitespace)) == 0)
114            continue;
115        if (user[0] == '/') {                   /* user */
116            path = user;
117        } else {                                /* path */
118            if ((path = strtok((char *) 0, whitespace)) == 0)
119                continue;
120        }
121        if (path[0] == '?')                     /* IRIX optional service */
122            path++;
123        if (STR_EQ(path, "internal"))
124            continue;
125        if (path[strspn(path, "-0123456789")] == 0) {
126
127            /*
128             * ConvexOS puts RPC version numbers before path names. Jukka
129             * Ukkonen <ukkonen@csc.fi>.
130             */
131            if ((path = strtok((char *) 0, whitespace)) == 0)
132                continue;
133        }
134        if ((arg0 = strtok((char *) 0, whitespace)) == 0) {
135            tcpd_warn("incomplete line");
136            continue;
137        }
138        if (arg0[strspn(arg0, "0123456789")] == 0) {
139
140            /*
141             * We're reading a tlid.conf file, the format is:
142             *
143             * ...stuff... path arg_count arguments mod_count modules
144             */
145            if ((arg0 = strtok((char *) 0, whitespace)) == 0) {
146                tcpd_warn("incomplete line");
147                continue;
148            }
149        }
150        if ((arg1 = strtok((char *) 0, whitespace)) == 0)
151            arg1 = "";
152
153        inet_chk(protocol, path, arg0, arg1);
154    }
155    fclose(fp);
156    tcpd_context = saved_context;
157    return (conf);
158}
159
160/* inet_chk - examine one inetd.conf (tlid.conf?) entry */
161
162static void inet_chk(protocol, path, arg0, arg1)
163char   *protocol;
164char   *path;
165char   *arg0;
166char   *arg1;
167{
168    char    daemon[BUFSIZ];
169    struct stat st;
170    int     wrap_status = WR_MAYBE;
171    char   *base_name_path = base_name(path);
172    char   *tcpd_proc_name = (arg0[0] == '/' ? base_name(arg0) : arg0);
173
174    /*
175     * Always warn when the executable does not exist or when it is not
176     * executable.
177     */
178    if (check_path(path, &st) < 0) {
179        tcpd_warn("%s: not found: %m", path);
180    } else if ((st.st_mode & 0100) == 0) {
181        tcpd_warn("%s: not executable", path);
182    }
183
184    /*
185     * Cheat on the miscd tests, nobody uses it anymore.
186     */
187    if (STR_EQ(base_name_path, "miscd")) {
188        inet_set(arg0, WR_YES);
189        return;
190    }
191
192    /*
193     * While we are here...
194     */
195    if (STR_EQ(tcpd_proc_name, "rexd") || STR_EQ(tcpd_proc_name, "rpc.rexd"))
196        tcpd_warn("%s may be an insecure service", tcpd_proc_name);
197
198    /*
199     * The tcpd program gets most of the attention.
200     */
201    if (STR_EQ(base_name_path, "tcpd")) {
202
203        if (STR_EQ(tcpd_proc_name, "tcpd"))
204            tcpd_warn("%s is recursively calling itself", tcpd_proc_name);
205
206        wrap_status = WR_YES;
207
208        /*
209         * Check: some sites install the wrapper set-uid.
210         */
211        if ((st.st_mode & 06000) != 0)
212            tcpd_warn("%s: file is set-uid or set-gid", path);
213
214        /*
215         * Check: some sites insert tcpd in inetd.conf, instead of replacing
216         * the daemon pathname.
217         */
218        if (arg0[0] == '/' && STR_EQ(tcpd_proc_name, base_name(arg1)))
219            tcpd_warn("%s inserted before %s", path, arg0);
220
221        /*
222         * Check: make sure files exist and are executable. On some systems
223         * the network daemons are set-uid so we cannot complain. Note that
224         * tcpd takes the basename only in case of absolute pathnames.
225         */
226        if (arg0[0] == '/') {                   /* absolute path */
227            if (check_path(arg0, &st) < 0) {
228                tcpd_warn("%s: not found: %m", arg0);
229            } else if ((st.st_mode & 0100) == 0) {
230                tcpd_warn("%s: not executable", arg0);
231            }
232        } else {                                /* look in REAL_DAEMON_DIR */
233            sprintf(daemon, "%s/%s", REAL_DAEMON_DIR, arg0);
234            if (check_path(daemon, &st) < 0) {
235                tcpd_warn("%s: not found in %s: %m",
236                          arg0, REAL_DAEMON_DIR);
237            } else if ((st.st_mode & 0100) == 0) {
238                tcpd_warn("%s: not executable", daemon);
239            }
240        }
241
242    } else {
243
244        /*
245         * No tcpd program found. Perhaps they used the "simple installation"
246         * recipe. Look for a file with the same basename in REAL_DAEMON_DIR.
247         * Draw some conservative conclusions when a distinct file is found.
248         */
249        sprintf(daemon, "%s/%s", REAL_DAEMON_DIR, arg0);
250        if (STR_EQ(path, daemon)) {
251            wrap_status = WR_NOT;
252        } else if (check_path(daemon, &st) >= 0) {
253            wrap_status = WR_MAYBE;
254        } else if (errno == ENOENT) {
255            wrap_status = WR_NOT;
256        } else {
257            tcpd_warn("%s: file lookup: %m", daemon);
258            wrap_status = WR_MAYBE;
259        }
260    }
261
262    /*
263     * Alas, we cannot wrap rpc/tcp services.
264     */
265    if (wrap_status == WR_YES && STR_EQ(protocol, "rpc/tcp"))
266        tcpd_warn("%s: cannot wrap rpc/tcp services", tcpd_proc_name);
267
268    inet_set(tcpd_proc_name, wrap_status);
269}
270
271/* inet_set - remember service status */
272
273void    inet_set(name, type)
274char   *name;
275int     type;
276{
277    struct inet_ent *ip =
278    (struct inet_ent *) malloc(sizeof(struct inet_ent) + strlen(name));
279
280    if (ip == 0) {
281        fprintf(stderr, "out of memory\n");
282        exit(1);
283    }
284    ip->next = inet_list;
285    strcpy(ip->name, name);
286    ip->type = type;
287    inet_list = ip;
288}
289
290/* inet_get - look up service status */
291
292int     inet_get(name)
293char   *name;
294{
295    struct inet_ent *ip;
296
297    if (inet_list == 0)
298        return (WR_MAYBE);
299
300    for (ip = inet_list; ip; ip = ip->next)
301        if (STR_EQ(ip->name, name))
302            return (ip->type);
303
304    return (-1);
305}
306
307/* base_name - compute last pathname component */
308
309static char *base_name(path)
310char   *path;
311{
312    char   *cp;
313
314    if ((cp = strrchr(path, '/')) != 0)
315        path = cp + 1;
316    return (path);
317}
Note: See TracBrowser for help on using the repository browser.