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
   9: static char sccsid[] = "@(#) inetcf.c 1.5 95/01/30 19:51:48";
  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: 
  18: extern int errno;
  19: extern 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:   */
  28: char   *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: 
  39: static void inet_chk();
  40: static char *base_name();
  41: 
  42:  /*
  43:   * Structure with everything we know about a service.
  44:   */
  45: struct inet_ent {
  46:     struct inet_ent *next;
  47:     int     type;
  48:     char    name[1];
  49: };
  50: 
  51: static struct inet_ent *inet_list = 0;
  52: 
  53: static char whitespace[] = " \t\r\n";
  54: 
  55: /* inet_conf - read in and examine inetd.conf (or tlid.conf) entries */
  56: 
  57: char   *inet_cfg(conf)
  58: char   *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 (STR_EQ(path, "internal"))
 122:         continue;
 123:     if (path[strspn(path, "-0123456789")] == 0) {
 124: 
 125:         /*
 126: 	     * ConvexOS puts RPC version numbers before path names. Jukka
 127: 	     * Ukkonen <ukkonen@csc.fi>.
 128: 	     */
 129:         if ((path = strtok((char *) 0, whitespace)) == 0)
 130:         continue;
 131:     }
 132:     if ((arg0 = strtok((char *) 0, whitespace)) == 0) {
 133:         tcpd_warn("incomplete line");
 134:         continue;
 135:     }
 136:     if (arg0[strspn(arg0, "0123456789")] == 0) {
 137: 
 138:         /*
 139: 	     * We're reading a tlid.conf file, the format is:
 140: 	     *
 141: 	     * ...stuff... path arg_count arguments mod_count modules
 142: 	     */
 143:         if ((arg0 = strtok((char *) 0, whitespace)) == 0) {
 144:         tcpd_warn("incomplete line");
 145:         continue;
 146:         }
 147:     }
 148:     if ((arg1 = strtok((char *) 0, whitespace)) == 0)
 149:         arg1 = "";
 150: 
 151:     inet_chk(protocol, path, arg0, arg1);
 152:     }
 153:     fclose(fp);
 154:     tcpd_context = saved_context;
 155:     return (conf);
 156: }
 157: 
 158: /* inet_chk - examine one inetd.conf (tlid.conf?) entry */
 159: 
 160: static void inet_chk(protocol, path, arg0, arg1)
 161: char   *protocol;
 162: char   *path;
 163: char   *arg0;
 164: char   *arg1;
 165: {
 166:     char    daemon[BUFSIZ];
 167:     struct stat st;
 168:     int     wrap_status = WR_MAYBE;
 169:     char   *base_name_path = base_name(path);
 170:     char   *tcpd_proc_name = (arg0[0] == '/' ? base_name(arg0) : arg0);
 171: 
 172:     /*
 173:      * Always warn when the executable does not exist or when it is not
 174:      * executable.
 175:      */
 176:     if (check_path(path, &st) < 0) {
 177:     tcpd_warn("%s: not found: %m", path);
 178:     } else if ((st.st_mode & 0100) == 0) {
 179:     tcpd_warn("%s: not executable", path);
 180:     }
 181: 
 182:     /*
 183:      * Cheat on the miscd tests, nobody uses it anymore.
 184:      */
 185:     if (STR_EQ(base_name_path, "miscd")) {
 186:     inet_set(arg0, WR_YES);
 187:     return;
 188:     }
 189: 
 190:     /*
 191:      * While we are here...
 192:      */
 193:     if (STR_EQ(tcpd_proc_name, "rexd") || STR_EQ(tcpd_proc_name, "rpc.rexd"))
 194:     tcpd_warn("%s may be an insecure service", tcpd_proc_name);
 195: 
 196:     /*
 197:      * The tcpd program gets most of the attention.
 198:      */
 199:     if (STR_EQ(base_name_path, "tcpd")) {
 200: 
 201:     wrap_status = WR_YES;
 202: 
 203:     /*
 204: 	 * Check: some sites install the wrapper set-uid.
 205: 	 */
 206:     if ((st.st_mode & 06000) != 0)
 207:         tcpd_warn("%s: file is set-uid or set-gid", path);
 208: 
 209:     /*
 210: 	 * Check: some sites insert tcpd in inetd.conf, instead of replacing
 211: 	 * the daemon pathname.
 212: 	 */
 213:     if (arg0[0] == '/' && STR_EQ(tcpd_proc_name, base_name(arg1)))
 214:         tcpd_warn("%s inserted before %s", path, arg0);
 215: 
 216:     /*
 217: 	 * Check: make sure files exist and are executable. On some systems
 218: 	 * the network daemons are set-uid so we cannot complain. Note that
 219: 	 * tcpd takes the basename only in case of absolute pathnames.
 220: 	 */
 221:     if (arg0[0] == '/') {           /* absolute path */
 222:         if (check_path(arg0, &st) < 0) {
 223:         tcpd_warn("%s: not found: %m", arg0);
 224:         } else if ((st.st_mode & 0100) == 0) {
 225:         tcpd_warn("%s: not executable", arg0);
 226:         }
 227:     } else {                /* look in REAL_DAEMON_DIR */
 228:         sprintf(daemon, "%s/%s", REAL_DAEMON_DIR, arg0);
 229:         if (check_path(daemon, &st) < 0) {
 230:         tcpd_warn("%s: not found in %s: %m",
 231:               arg0, REAL_DAEMON_DIR);
 232:         } else if ((st.st_mode & 0100) == 0) {
 233:         tcpd_warn("%s: not executable", daemon);
 234:         }
 235:     }
 236: 
 237:     } else {
 238: 
 239:     /*
 240: 	 * No tcpd program found. Perhaps they used the "simple installation"
 241: 	 * recipe. Look for a file with the same basename in REAL_DAEMON_DIR.
 242: 	 * Draw some conservative conclusions when a distinct file is found.
 243: 	 */
 244:     sprintf(daemon, "%s/%s", REAL_DAEMON_DIR, arg0);
 245:     if (STR_EQ(path, daemon)) {
 246:         wrap_status = WR_NOT;
 247:     } else if (check_path(daemon, &st) >= 0) {
 248:         wrap_status = WR_MAYBE;
 249:     } else if (errno == ENOENT) {
 250:         wrap_status = WR_NOT;
 251:     } else {
 252:         tcpd_warn("%s: file lookup: %m", daemon);
 253:         wrap_status = WR_MAYBE;
 254:     }
 255:     }
 256: 
 257:     /*
 258:      * Alas, we cannot wrap rpc/tcp services.
 259:      */
 260:     if (wrap_status == WR_YES && STR_EQ(protocol, "rpc/tcp"))
 261:     tcpd_warn("%s: cannot wrap rpc/tcp services", tcpd_proc_name);
 262: 
 263:     inet_set(tcpd_proc_name, wrap_status);
 264: }
 265: 
 266: /* inet_set - remember service status */
 267: 
 268: void    inet_set(name, type)
 269: char   *name;
 270: int     type;
 271: {
 272:     struct inet_ent *ip =
 273:     (struct inet_ent *) malloc(sizeof(struct inet_ent) + strlen(name));
 274: 
 275:     if (ip == 0) {
 276:     fprintf(stderr, "out of memory\n");
 277:     exit(1);
 278:     }
 279:     ip->next = inet_list;
 280:     strcpy(ip->name, name);
 281:     ip->type = type;
 282:     inet_list = ip;
 283: }
 284: 
 285: /* inet_get - look up service status */
 286: 
 287: int     inet_get(name)
 288: char   *name;
 289: {
 290:     struct inet_ent *ip;
 291: 
 292:     if (inet_list == 0)
 293:     return (WR_MAYBE);
 294: 
 295:     for (ip = inet_list; ip; ip = ip->next)
 296:     if (STR_EQ(ip->name, name))
 297:         return (ip->type);
 298: 
 299:     return (-1);
 300: }
 301: 
 302: /* base_name - compute last pathname component */
 303: 
 304: static char *base_name(path)
 305: char   *path;
 306: {
 307:     char   *cp;
 308: 
 309:     if ((cp = strrchr(path, '/')) != 0)
 310:     path = cp + 1;
 311:     return (path);
 312: }

Defined functions

base_name defined in line 304; used 4 times
inet_chk defined in line 160; used 2 times
inet_set defined in line 268; used 9 times

Defined variables

inet_files defined in line 28; used 3 times
inet_list defined in line 51; used 4 times
sccsid defined in line 9; never used
whitespace defined in line 53; used 10 times

Defined struct's

inet_ent defined in line 45; used 12 times
Last modified: 1995-01-30
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3228
Valid CSS Valid XHTML 1.0 Strict