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