# 2.11BSD#431 - /usr/src/libexec/tcpd/tcpdchk.c

##### Functions

    main              X

##### Variables

    hosts_access_verboseX
    hosts_allow_table X
    hosts_deny_table  X

##### Macros

    BUFLEN            X
    DENY              X
    INADDR_NONE       X
    NO                X
    PERMIT            X
    YES               X

       1:  /*
       2:   * tcpdchk - examine all tcpd access control rules and inetd.conf entries
       3:   *
       4:   * Usage: tcpdchk [-a] [-d] [-i inet_conf] [-v]
       5:   *
       6:   * -a: complain about implicit "allow" at end of rule.
       7:   *
       8:   * -d: rules in current directory.
       9:   *
      10:   * -i: location of inetd.conf file.
      11:   *
      12:   * -v: show all rules.
      13:   *
      14:   * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
      15:   */
      16:
      17: #ifndef lint
      18: static char sccsid[] = "@(#) tcpdchk.c 1.6 95/01/30 19:51:51";
      19: #endif
      20:
      21: /* System libraries. */
      22:
      23: #include <sys/types.h>
      24: #include <sys/stat.h>
      25: #include <netinet/in.h>
      26: #include <arpa/inet.h>
      27: #include <stdio.h>
      28: #include <syslog.h>
      29: #include <setjmp.h>
      30: #include <errno.h>
      31: #include <netdb.h>
      32: #include <string.h>
      33:
      34: extern int errno;
      35: extern void exit();
      36: extern int optind;
      37: extern char *optarg;
      38:
      39: #ifndef INADDR_NONE
      40: #define INADDR_NONE     (-1)        /* XXX should be 0xffffffff */
      41: #endif
      42:
      43: /* Application-specific. */
      44:
      45: #include "tcpd.h"
      46: #include "inetcf.h"
      47: #include "scaffold.h"
      48:
      49:  /*
      50:   * Stolen from hosts_access.c...
      51:   */
      52: static char sep[] = ", \t\n";
      53:
      54: #define BUFLEN 2048
      55:
      56: int     hosts_access_verbose = 0;
      57: char   *hosts_allow_table = HOSTS_ALLOW;
      58: char   *hosts_deny_table = HOSTS_DENY;
      59: extern jmp_buf tcpd_buf;
      60:
      61:  /*
      62:   * Local stuff.
      63:   */
      64: static void usage();
      65: static void parse_table();
      66: static void print_list();
      67: static void check_daemon_list();
      68: static void check_client_list();
      69: static void check_daemon();
      70: static void check_user();
      71: static int check_host();
      72: static int reserved_name();
      73:
      74: #define PERMIT  1
      75: #define DENY    0
      76:
      77: #define YES 1
      78: #define NO  0
      79:
      80: static int defl_verdict;
      81: static char *myname;
      82: static int allow_check;
      83: static char *inetcf;
      84:
      85: int     main(argc, argv)
      86: int     argc;
      87: char  **argv;
      88: {
      89:     struct request_info request;
      90:     struct stat st;
      91:     int     c;
      92:
      93:     myname = argv[0];
      94:
      95:     /*
      96:      * Parse the JCL.
      97:      */
      98:     while ((c = getopt(argc, argv, "adi:v")) != EOF) {
      99:     switch (c) {
     100:     case 'a':
     101:         allow_check = 1;
     102:         break;
     103:     case 'd':
     104:         hosts_allow_table = "hosts.allow";
     105:         hosts_deny_table = "hosts.deny";
     106:         break;
     107:     case 'i':
     108:         inetcf = optarg;
     109:         break;
     110:     case 'v':
     111:         hosts_access_verbose++;
     112:         break;
     113:     default:
     114:         usage();
     115:         /* NOTREACHED */
     116:     }
     117:     }
     118:     if (argc != optind)
     119:     usage();
     120:
     121:     /*
     122:      * Process the inet configuration file (or its moral equivalent). This
     123:      * information is used later to find references in hosts.allow/deny to
     124:      * unwrapped services, and other possible problems.
     125:      */
     126:     inetcf = inet_cfg(inetcf);
     127:     if (hosts_access_verbose)
     128:     printf("Using network configuration file: %s\n", inetcf);
     129:
     130:     /*
     131:      * These are not run from inetd but may have built-in access control.
     132:      */
     133:     inet_set("portmap", WR_NOT);
     134:     inet_set("rpcbind", WR_NOT);
     135:
     136:     /*
     137:      * Check accessibility of access control files.
     138:      */
     139:     (void) check_path(hosts_allow_table, &st);
     140:     (void) check_path(hosts_deny_table, &st);
     141:
     142:     /*
     143:      * Fake up an arbitrary service request.
     144:      */
     145:     request_init(&request,
     146:          RQ_DAEMON, "daemon_name",
     147:          RQ_SERVER_NAME, "server_hostname",
     148:          RQ_SERVER_ADDR, "server_addr",
     149:          RQ_USER, "user_name",
     150:          RQ_CLIENT_NAME, "client_hostname",
     151:          RQ_CLIENT_ADDR, "client_addr",
     152:          RQ_FILE, 1,
     153:          0);
     154:
     155:     /*
     156:      * Examine all access-control rules.
     157:      */
     158:     defl_verdict = PERMIT;
     159:     parse_table(hosts_allow_table, &request);
     160:     defl_verdict = DENY;
     161:     parse_table(hosts_deny_table, &request);
     162:     return (0);
     163: }
     164:
     165: /* usage - explain */
     166:
     167: static void usage()
     168: {
     169:     fprintf(stderr, "usage: %s [-a] [-d] [-i inet_conf] [-v]\n", myname);
     170:     fprintf(stderr, "	-a: report rules with implicit \"ALLOW\" at end\n");
     171:     fprintf(stderr, "	-d: use allow/deny files in current directory\n");
     172:     fprintf(stderr, "	-i: location of inetd.conf file\n");
     173:     fprintf(stderr, "	-v: list all rules\n");
     174:     exit(1);
     175: }
     176:
     177: /* parse_table - like table_match(), but examines _all_ entries */
     178:
     179: static void parse_table(table, request)
     180: char   *table;
     181: struct request_info *request;
     182: {
     183:     FILE   *fp;
     184:     int     real_verdict;
     185:     char    sv_list[BUFLEN];        /* becomes list of daemons */
     186:     char   *cl_list;            /* becomes list of requests */
     187:     char   *sh_cmd;         /* becomes optional shell command */
     188:     char    buf[BUFSIZ];
     189:     int     verdict;
     190:     struct tcpd_context saved_context;
     191:
     192:     saved_context = tcpd_context;       /* stupid compilers */
     193:
     194:     if (fp = fopen(table, "r")) {
     195:     tcpd_context.file = table;
     196:     tcpd_context.line = 0;
     197:     while (xgets(sv_list, sizeof(sv_list), fp)) {
     198:         if (sv_list[strlen(sv_list) - 1] != '\n') {
     199:         tcpd_warn("missing newline or line too long");
     200:         continue;
     201:         }
     202:         if (sv_list[0] == '#' || sv_list[strspn(sv_list, " \t\r\n")] == 0)
     203:         continue;
     204:         if ((cl_list = split_at(sv_list, ':')) == 0) {
     205:         tcpd_warn("missing \":\" separator");
     206:         continue;
     207:         }
     208:         sh_cmd = split_at(cl_list, ':');
     209:
     210:         if (hosts_access_verbose)
     211:         printf("\n>>> Rule %s line %d:\n",
     212:                tcpd_context.file, tcpd_context.line);
     213:
     214:         if (hosts_access_verbose)
     215:         print_list("daemons:  ", sv_list);
     216:         check_daemon_list(sv_list);
     217:
     218:         if (hosts_access_verbose)
     219:         print_list("clients:  ", cl_list);
     220:         check_client_list(cl_list);
     221:
     222: #ifdef PROCESS_OPTIONS
     223:         real_verdict = defl_verdict;
     224:         if (sh_cmd) {
     225:         if ((verdict = setjmp(tcpd_buf)) != 0) {
     226:             real_verdict = (verdict == AC_PERMIT);
     227:         } else {
     228:             dry_run = 1;
     229:             process_options(sh_cmd, request);
     230:             if (dry_run == 1 && real_verdict && allow_check)
     231:             tcpd_warn("implicit \"allow\" at end of rule");
     232:         }
     233:         } else if (defl_verdict && allow_check) {
     234:         tcpd_warn("implicit \"allow\" at end of rule");
     235:         }
     236:         if (hosts_access_verbose)
     237:         printf("access:   %s\n", real_verdict ? "granted" : "denied");
     238: #else
     239:         if (sh_cmd)
     240:         shell_cmd(percent_x(buf, sizeof(buf), sh_cmd, request));
     241:         if (hosts_access_verbose)
     242:         printf("access:   %s\n", defl_verdict ? "granted" : "denied");
     243: #endif
     244:     }
     245:     (void) fclose(fp);
     246:     } else if (errno != ENOENT) {
     247:     tcpd_warn("cannot open %s: %m", table);
     248:     }
     249:     tcpd_context = saved_context;
     250: }
     251:
     252: /* print_list - pretty-print a list */
     253:
     254: static void print_list(title, list)
     255: char   *title;
     256: char   *list;
     257: {
     258:     char    buf[BUFLEN];
     259:     char   *cp;
     260:     char   *next;
     261:
     262:     fputs(title, stdout);
     263:     strcpy(buf, list);
     264:
     265:     for (cp = strtok(buf, sep); cp != 0; cp = next) {
     266:     fputs(cp, stdout);
     267:     next = strtok((char *) 0, sep);
     268:     if (next != 0)
     269:         fputs(" ", stdout);
     270:     }
     271:     fputs("\n", stdout);
     272: }
     273:
     274: /* check_daemon_list - criticize daemon list */
     275:
     276: static void check_daemon_list(list)
     277: char   *list;
     278: {
     279:     char    buf[BUFLEN];
     280:     char   *cp;
     281:     char   *host;
     282:     int     daemons = 0;
     283:
     284:     strcpy(buf, list);
     285:
     286:     for (cp = strtok(buf, sep); cp != 0; cp = strtok((char *) 0, sep)) {
     287:     if (STR_EQ(cp, "EXCEPT")) {
     288:         daemons = 0;
     289:     } else {
     290:         daemons++;
     291:         if ((host = split_at(cp + 1, '@')) != 0 && check_host(host) > 1) {
     292:         tcpd_warn("host %s has more than one address", host);
     293:         tcpd_warn("(consider using an address instead)");
     294:         }
     295:         check_daemon(cp);
     296:     }
     297:     }
     298:     if (daemons == 0)
     299:     tcpd_warn("daemon list is empty or ends in EXCEPT");
     300: }
     301:
     302: /* check_client_list - criticize client list */
     303:
     304: static void check_client_list(list)
     305: char   *list;
     306: {
     307:     char    buf[BUFLEN];
     308:     char   *cp;
     309:     char   *host;
     310:     int     clients = 0;
     311:
     312:     strcpy(buf, list);
     313:
     314:     for (cp = strtok(buf, sep); cp != 0; cp = strtok((char *) 0, sep)) {
     315:     if (STR_EQ(cp, "EXCEPT")) {
     316:         clients = 0;
     317:     } else {
     318:         clients++;
     319:         if (host = split_at(cp + 1, '@')) { /* user@host */
     320:         check_user(cp);
     321:         check_host(host);
     322:         } else {
     323:         check_host(cp);
     324:         }
     325:     }
     326:     }
     327:     if (clients == 0)
     328:     tcpd_warn("client list is empty or ends in EXCEPT");
     329: }
     330:
     331: /* check_daemon - criticize daemon pattern */
     332:
     333: static void check_daemon(pat)
     334: char   *pat;
     335: {
     336:     if (pat[0] == '@') {
     337:     tcpd_warn("%s: daemon name begins with \"@\"", pat);
     338:     } else if (pat[0] == '.') {
     339:     tcpd_warn("%s: daemon name begins with dot", pat);
     340:     } else if (pat[strlen(pat) - 1] == '.') {
     341:     tcpd_warn("%s: daemon name ends in dot", pat);
     342:     } else if (STR_EQ(pat, "ALL") || STR_EQ(pat, unknown)) {
     343:      /* void */ ;
     344:     } else if (STR_EQ(pat, "FAIL")) {       /* obsolete */
     345:     tcpd_warn("FAIL is no longer recognized");
     346:     tcpd_warn("(use EXCEPT or DENY instead)");
     347:     } else if (reserved_name(pat)) {
     348:     tcpd_warn("%s: daemon name may be reserved word", pat);
     349:     } else {
     350:     switch (inet_get(pat)) {
     351:     case WR_UNKNOWN:
     352:         tcpd_warn("%s: no such process name in %s", pat, inetcf);
     353:         inet_set(pat, WR_YES);      /* shut up next time */
     354:         break;
     355:     case WR_NOT:
     356:         tcpd_warn("%s: service possibly not wrapped", pat);
     357:         inet_set(pat, WR_YES);
     358:         break;
     359:     }
     360:     }
     361: }
     362:
     363: /* check_user - criticize user pattern */
     364:
     365: static void check_user(pat)
     366: char   *pat;
     367: {
     368:     if (pat[0] == '@') {            /* @netgroup */
     369:     tcpd_warn("%s: user name begins with \"@\"", pat);
     370:     } else if (pat[0] == '.') {
     371:     tcpd_warn("%s: user name begins with dot", pat);
     372:     } else if (pat[strlen(pat) - 1] == '.') {
     373:     tcpd_warn("%s: user name ends in dot", pat);
     374:     } else if (STR_EQ(pat, "ALL") || STR_EQ(pat, unknown)
     375:            || STR_EQ(pat, "KNOWN")) {
     376:      /* void */ ;
     377:     } else if (STR_EQ(pat, "FAIL")) {       /* obsolete */
     378:     tcpd_warn("FAIL is no longer recognized");
     379:     tcpd_warn("(use EXCEPT or DENY instead)");
     380:     } else if (reserved_name(pat)) {
     381:     tcpd_warn("%s: user name may be reserved word", pat);
     382:     }
     383: }
     384:
     385: /* check_host - criticize host pattern */
     386:
     387: static int check_host(pat)
     388: char   *pat;
     389: {
     390:     char   *mask;
     391:     int     addr_count = 1;
     392:
     393:     if (pat[0] == '@') {            /* @netgroup */
     394: #ifdef NO_NETGRENT
     395:     /* SCO has no *netgrent() support */
     396: #else
     397: #ifdef NETGROUP
     398:     char   *machinep;
     399:     char   *userp;
     400:     char   *domainp;
     401:
     402:     setnetgrent(pat + 1);
     403:     if (getnetgrent(&machinep, &userp, &domainp) == 0)
     404:         tcpd_warn("%s: unknown or empty netgroup", pat + 1);
     405:     endnetgrent();
     406: #else
     407:     tcpd_warn("netgroup support disabled");
     408: #endif
     409: #endif
     410:     } else if (mask = split_at(pat, '/')) { /* network/netmask */
     411:     if (dot_quad_addr(pat) == INADDR_NONE
     412:         || dot_quad_addr(mask) == INADDR_NONE)
     413:         tcpd_warn("%s/%s: bad net/mask pattern", pat, mask);
     414:     } else if (STR_EQ(pat, "FAIL")) {       /* obsolete */
     415:     tcpd_warn("FAIL is no longer recognized");
     416:     tcpd_warn("(use EXCEPT or DENY instead)");
     417:     } else if (reserved_name(pat)) {        /* other reserved */
     418:      /* void */ ;
     419:     } else if (NOT_INADDR(pat)) {       /* internet name */
     420:     if (pat[strlen(pat) - 1] == '.') {
     421:         tcpd_warn("%s: domain or host name ends in dot", pat);
     422:     } else if (pat[0] != '.') {
     423:         addr_count = check_dns(pat);
     424:     }
     425:     } else {                    /* numeric form */
     426:     if (STR_EQ(pat, "0.0.0.0") || STR_EQ(pat, "255.255.255.255")) {
     427:         /* void */ ;
     428:     } else if (pat[0] == '.') {
     429:         tcpd_warn("%s: network number begins with dot", pat);
     430:     } else if (pat[strlen(pat) - 1] != '.') {
     431:         check_dns(pat);
     432:     }
     433:     }
     434:     return (addr_count);
     435: }
     436:
     437: /* reserved_name - determine if name is reserved */
     438:
     439: static int reserved_name(pat)
     440: char   *pat;
     441: {
     442:     return (STR_EQ(pat, unknown)
     443:         || STR_EQ(pat, "KNOWN")
     444:         || STR_EQ(pat, paranoid)
     445:         || STR_EQ(pat, "ALL")
     446:         || STR_EQ(pat, "LOCAL"));
     447: }

#### Defined functions

check_client_list defined in line 304; used 2 times

- in line 68, 220

check_daemon defined in line 333; used 2 times

- in line 69, 295

check_daemon_list defined in line 276; used 2 times

- in line 67, 216

check_host defined in line 387; used 4 times

- in line 71, 291, 321-323(2)

check_user defined in line 365; used 2 times

- in line 70, 320

main defined in line 85; never used
parse_table defined in line 179; used 3 times

- in line 65, 159-161(2)

print_list defined in line 254; used 3 times

- in line 66, 215-219(2)

reserved_name defined in line 439; used 4 times

- in line 72, 347, 380, 417

usage defined in line 167; used 3 times

- in line 64, 114-119(2)

#### Defined variables

allow_check defined in line 82; used 3 times

- in line 101, 230-233(2)

defl_verdict defined in line 80; used 5 times

- in line 158-160(2), 223, 233, 242

hosts_access_verbose defined in line 56; used 7 times

- in line 111, 127, 210-218(3), 236-241(2)

hosts_allow_table defined in line 57; used 3 times

- in line 104, 139, 159

hosts_deny_table defined in line 58; used 3 times

- in line 105, 140, 161

inetcf defined in line 83; used 5 times

- in line 108, 126-128(3), 352

myname defined in line 81; used 2 times

- in line 93, 169

sccsid defined in line 18; never used
sep defined in line 52; used 6 times

- in line 265-267(2), 286(2), 314(2)

#### Defined macros

BUFLEN defined in line 54; used 4 times

- in line 185, 258, 279, 307

DENY defined in line 75; used 1 times

- in line 160

INADDR_NONE defined in line 40; used 3 times

- in line 39, 411-412(2)

NO defined in line 78; never used
PERMIT defined in line 74; used 1 times

- in line 158

YES defined in line 77; never used

Last modified: 1995-01-30 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 1625 |