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