1:  /*
   2:   * tcpdmatch - explain what tcpd would do in a specific case
   3:   *
   4:   * usage: tcpdmatch [-d] [-i inet_conf] daemon[@host] [user@]host
   5:   *
   6:   * -d: use the access control tables in the current directory.
   7:   *
   8:   * -i: location of inetd.conf file.
   9:   *
  10:   * All errors are reported to the standard error stream, including the errors
  11:   * that would normally be reported via the syslog daemon.
  12:   *
  13:   * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
  14:   */
  15: 
  16: #ifndef lint
  17: static char sccsid[] = "@(#) tcpdmatch.c 1.4 95/01/01 13:34:07";
  18: #endif
  19: 
  20: /* System libraries. */
  21: 
  22: #include <sys/types.h>
  23: #include <sys/stat.h>
  24: #include <sys/socket.h>
  25: #include <netinet/in.h>
  26: #include <arpa/inet.h>
  27: #include <netdb.h>
  28: #include <stdio.h>
  29: #include <syslog.h>
  30: #include <setjmp.h>
  31: #include <string.h>
  32: 
  33: extern void exit();
  34: extern int optind;
  35: extern char *optarg;
  36: 
  37: #ifndef INADDR_NONE
  38: #define INADDR_NONE (-1)        /* XXX should be 0xffffffff */
  39: #endif
  40: 
  41: /* Application-specific. */
  42: 
  43: #include "tcpd.h"
  44: #include "inetcf.h"
  45: #include "scaffold.h"
  46: 
  47: static void usage();
  48: static void tcpdmatch();
  49: 
  50: /* The main program */
  51: 
  52: int     main(argc, argv)
  53: int     argc;
  54: char  **argv;
  55: {
  56:     struct hostent *hp;
  57:     char   *myname = argv[0];
  58:     char   *client;
  59:     char   *server;
  60:     char   *addr;
  61:     char   *user;
  62:     char   *daemon;
  63:     struct request_info request;
  64:     int     ch;
  65:     char   *inetcf = 0;
  66:     int     count;
  67:     struct sockaddr_in server_sin;
  68:     struct sockaddr_in client_sin;
  69:     struct stat st;
  70: 
  71:     /*
  72:      * Show what rule actually matched.
  73:      */
  74:     hosts_access_verbose = 2;
  75: 
  76:     /*
  77:      * Parse the JCL.
  78:      */
  79:     while ((ch = getopt(argc, argv, "di:")) != EOF) {
  80:     switch (ch) {
  81:     case 'd':
  82:         hosts_allow_table = "hosts.allow";
  83:         hosts_deny_table = "hosts.deny";
  84:         break;
  85:     case 'i':
  86:         inetcf = optarg;
  87:         break;
  88:     default:
  89:         usage(myname);
  90:         /* NOTREACHED */
  91:     }
  92:     }
  93:     if (argc != optind + 2)
  94:     usage(myname);
  95: 
  96:     /*
  97:      * Default is to specify a daemon process name. When daemon@host is
  98:      * specified, separate the two parts.
  99:      */
 100:     if ((server = split_at(argv[optind], '@')) == 0)
 101:     server = unknown;
 102:     if (argv[optind][0] == '/') {
 103:     daemon = strrchr(argv[optind], '/') + 1;
 104:     tcpd_warn("%s: daemon name normalized to: %s", argv[optind], daemon);
 105:     } else {
 106:     daemon = argv[optind];
 107:     }
 108: 
 109:     /*
 110:      * Default is to specify a client hostname or address. When user@host is
 111:      * specified, separate the two parts.
 112:      */
 113:     if ((client = split_at(argv[optind + 1], '@')) != 0) {
 114:     user = argv[optind + 1];
 115:     } else {
 116:     client = argv[optind + 1];
 117:     user = unknown;
 118:     }
 119: 
 120:     /*
 121:      * Analyze the inetd (or tlid) configuration file, so that we can warn
 122:      * the user about services that may not be wrapped, services that are not
 123:      * configured, or services that are wrapped in an incorrect manner. Allow
 124:      * for services that are not run from inetd, or that have tcpd access
 125:      * control built into them.
 126:      */
 127:     inetcf = inet_cfg(inetcf);
 128:     inet_set("portmap", WR_NOT);
 129:     inet_set("rpcbind", WR_NOT);
 130:     switch (inet_get(daemon)) {
 131:     case WR_UNKNOWN:
 132:     tcpd_warn("%s: no such process name in %s", daemon, inetcf);
 133:     break;
 134:     case WR_NOT:
 135:     tcpd_warn("%s: service possibly not wrapped", daemon);
 136:     break;
 137:     }
 138: 
 139:     /*
 140:      * Check accessibility of access control files.
 141:      */
 142:     (void) check_path(hosts_allow_table, &st);
 143:     (void) check_path(hosts_deny_table, &st);
 144: 
 145:     /*
 146:      * Fill in what we have figured out sofar. Use socket and DNS routines
 147:      * for address and name conversions. We attach stdout to the request so
 148:      * that banner messages will become visible.
 149:      */
 150:     request_init(&request, RQ_DAEMON, daemon, RQ_USER, user, RQ_FILE, 1, 0);
 151:     sock_methods(&request);
 152: 
 153:     /*
 154:      * If a server hostname is specified, insist that the name maps to at
 155:      * most one address. eval_hostname() warns the user about name server
 156:      * problems, while using the request.server structure as a cache for host
 157:      * address and name conversion results.
 158:      */
 159:     if (NOT_INADDR(server) == 0 || HOSTNAME_KNOWN(server)) {
 160:     if ((hp = find_inet_addr(server)) == 0)
 161:         exit(1);
 162:     memset((char *) &server_sin, 0, sizeof(server_sin));
 163:     server_sin.sin_family = AF_INET;
 164:     request_set(&request, RQ_SERVER_SIN, &server_sin, 0);
 165: 
 166:     for (count = 0; (addr = hp->h_addr_list[count]) != 0; count++) {
 167:         memcpy((char *) &server_sin.sin_addr, addr,
 168:            sizeof(server_sin.sin_addr));
 169: 
 170:         /*
 171: 	     * Force evaluation of server host name and address. Host name
 172: 	     * conflicts will be reported while eval_hostname() does its job.
 173: 	     */
 174:         request_set(&request, RQ_SERVER_NAME, "", RQ_SERVER_ADDR, "", 0);
 175:         if (STR_EQ(eval_hostname(request.server), unknown))
 176:         tcpd_warn("host address %s->name lookup failed",
 177:               eval_hostaddr(request.server));
 178:     }
 179:     if (count > 1) {
 180:         fprintf(stderr, "Error: %s has more than one address\n", server);
 181:         fprintf(stderr, "Please specify an address instead\n");
 182:         exit(1);
 183:     }
 184:     free((char *) hp);
 185:     } else {
 186:     request_set(&request, RQ_SERVER_NAME, server, 0);
 187:     }
 188: 
 189:     /*
 190:      * If a client address is specified, we simulate the effect of client
 191:      * hostname lookup failure.
 192:      */
 193:     if (dot_quad_addr(client) != INADDR_NONE) {
 194:     request_set(&request, RQ_CLIENT_ADDR, client, 0);
 195:     tcpdmatch(&request);
 196:     exit(0);
 197:     }
 198: 
 199:     /*
 200:      * Perhaps they are testing special client hostname patterns that aren't
 201:      * really host names at all.
 202:      */
 203:     if (NOT_INADDR(client) && HOSTNAME_KNOWN(client) == 0) {
 204:     request_set(&request, RQ_CLIENT_NAME, client, 0);
 205:     tcpdmatch(&request);
 206:     exit(0);
 207:     }
 208: 
 209:     /*
 210:      * Otherwise, assume that a client hostname is specified, and insist that
 211:      * the address can be looked up. The reason for this requirement is that
 212:      * in real life the client address is available (at least with IP). Let
 213:      * eval_hostname() figure out if this host is properly registered, while
 214:      * using the request.client structure as a cache for host name and
 215:      * address conversion results.
 216:      */
 217:     if ((hp = find_inet_addr(client)) == 0)
 218:     exit(1);
 219:     memset((char *) &client_sin, 0, sizeof(client_sin));
 220:     client_sin.sin_family = AF_INET;
 221:     request_set(&request, RQ_CLIENT_SIN, &client_sin, 0);
 222: 
 223:     for (count = 0; (addr = hp->h_addr_list[count]) != 0; count++) {
 224:     memcpy((char *) &client_sin.sin_addr, addr,
 225:            sizeof(client_sin.sin_addr));
 226: 
 227:     /*
 228: 	 * Force evaluation of client host name and address. Host name
 229: 	 * conflicts will be reported while eval_hostname() does its job.
 230: 	 */
 231:     request_set(&request, RQ_CLIENT_NAME, "", RQ_CLIENT_ADDR, "", 0);
 232:     if (STR_EQ(eval_hostname(request.client), unknown))
 233:         tcpd_warn("host address %s->name lookup failed",
 234:               eval_hostaddr(request.client));
 235:     tcpdmatch(&request);
 236:     if (hp->h_addr_list[count + 1])
 237:         printf("\n");
 238:     }
 239:     free((char *) hp);
 240:     exit(0);
 241: }
 242: 
 243: /* Explain how to use this program */
 244: 
 245: static void usage(myname)
 246: char   *myname;
 247: {
 248:     fprintf(stderr, "usage: %s [-d] [-i inet_conf] daemon[@host] [user@]host\n",
 249:         myname);
 250:     fprintf(stderr, "	-d: use allow/deny files in current directory\n");
 251:     fprintf(stderr, "	-i: location of inetd.conf file\n");
 252:     exit(1);
 253: }
 254: 
 255: /* Print interesting expansions */
 256: 
 257: static void expand(text, pattern, request)
 258: char   *text;
 259: char   *pattern;
 260: struct request_info *request;
 261: {
 262:     char    buf[BUFSIZ];
 263: 
 264:     if (STR_NE(percent_x(buf, sizeof(buf), pattern, request), unknown))
 265:     printf("%s %s\n", text, buf);
 266: }
 267: 
 268: /* Try out a (server,client) pair */
 269: 
 270: static void tcpdmatch(request)
 271: struct request_info *request;
 272: {
 273:     int     verdict;
 274: 
 275:     /*
 276:      * Show what we really know. Suppress uninteresting noise.
 277:      */
 278:     expand("client:   hostname", "%n", request);
 279:     expand("client:   address ", "%a", request);
 280:     expand("client:   username", "%u", request);
 281:     expand("server:   hostname", "%N", request);
 282:     expand("server:   address ", "%A", request);
 283:     expand("server:   process ", "%d", request);
 284: 
 285:     /*
 286:      * Reset stuff that might be changed by options handlers. In dry-run
 287:      * mode, extension language routines that would not return should inform
 288:      * us of their plan, by clearing the dry_run flag. This is a bit clumsy
 289:      * but we must be able to verify hosts with more than one network
 290:      * address.
 291:      */
 292:     rfc931_timeout = RFC931_TIMEOUT;
 293:     allow_severity = SEVERITY;
 294:     deny_severity = LOG_WARNING;
 295:     dry_run = 1;
 296: 
 297:     /*
 298:      * When paranoid mode is enabled, access is rejected no matter what the
 299:      * access control rules say.
 300:      */
 301: #ifdef PARANOID
 302:     if (STR_EQ(eval_hostname(request->client), paranoid)) {
 303:     printf("access:   denied (PARANOID mode)\n\n");
 304:     return;
 305:     }
 306: #endif
 307: 
 308:     /*
 309:      * Report the access control verdict.
 310:      */
 311:     verdict = hosts_access(request);
 312:     printf("access:   %s\n",
 313:        dry_run == 0 ? "delegated" :
 314:        verdict ? "granted" : "denied");
 315: }

Defined functions

expand defined in line 257; used 6 times
main defined in line 52; never used
tcpdmatch defined in line 270; used 4 times
usage defined in line 245; used 3 times

Defined variables

sccsid defined in line 17; never used

Defined macros

INADDR_NONE defined in line 38; used 2 times
Last modified: 1995-01-01
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1004
Valid CSS Valid XHTML 1.0 Strict