1 /* $NetBSD: scaffold.c,v 1.3 1997/11/16 21:30:25 christos Exp $ */ 2 3 /* 4 * Routines for testing only. Not really industrial strength. 5 * 6 * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands. 7 */ 8 9 #include <sys/cdefs.h> 10 #ifndef lint 11 #if 0 12 static char sccs_id[] = "@(#) scaffold.c 1.5 95/01/03 09:13:48"; 13 #else 14 __RCSID("$NetBSD: scaffold.c,v 1.3 1997/11/16 21:30:25 christos Exp $"); 15 #endif 16 #endif 17 18 /* System libraries. */ 19 20 #include <sys/types.h> 21 #include <sys/stat.h> 22 #include <sys/socket.h> 23 #include <netinet/in.h> 24 #include <arpa/inet.h> 25 #include <netdb.h> 26 #include <stdio.h> 27 #include <syslog.h> 28 #include <setjmp.h> 29 #include <string.h> 30 #include <stdlib.h> 31 32 #ifndef INADDR_NONE 33 #define INADDR_NONE (-1) /* XXX should be 0xffffffff */ 34 #endif 35 36 /* Application-specific. */ 37 38 #include "tcpd.h" 39 #include "scaffold.h" 40 41 static struct hostent *dup_hostent __P((struct hostent *)); 42 43 /* 44 * These are referenced by the options module and by rfc931.c. 45 */ 46 int allow_severity = SEVERITY; 47 int deny_severity = LOG_WARNING; 48 extern int rfc931_timeout; /* = RFC931_TIMEOUT; */ 49 50 /* dup_hostent - create hostent in one memory block */ 51 52 static struct hostent *dup_hostent(hp) 53 struct hostent *hp; 54 { 55 struct hostent_block { 56 struct hostent host; 57 char *addr_list[1]; 58 }; 59 struct hostent_block *hb; 60 int count; 61 char *data; 62 char *addr; 63 64 for (count = 0; hp->h_addr_list[count] != 0; count++) 65 /* void */ ; 66 67 if ((hb = (struct hostent_block *) malloc(sizeof(struct hostent_block) 68 + (hp->h_length + sizeof(char *)) * count)) == 0) { 69 fprintf(stderr, "Sorry, out of memory\n"); 70 exit(1); 71 } 72 memset((char *) &hb->host, 0, sizeof(hb->host)); 73 hb->host.h_length = hp->h_length; 74 hb->host.h_addr_list = hb->addr_list; 75 hb->host.h_addr_list[count] = 0; 76 data = (char *) (hb->host.h_addr_list + count + 1); 77 78 for (count = 0; (addr = hp->h_addr_list[count]) != 0; count++) { 79 hb->host.h_addr_list[count] = data + hp->h_length * count; 80 memcpy(hb->host.h_addr_list[count], addr, hp->h_length); 81 } 82 return (&hb->host); 83 } 84 85 /* find_inet_addr - find all addresses for this host, result to free() */ 86 87 struct hostent *find_inet_addr(host) 88 char *host; 89 { 90 struct in_addr addr; 91 struct hostent *hp; 92 static struct hostent h; 93 static char *addr_list[2]; 94 95 /* 96 * Host address: translate it to internal form. 97 */ 98 if ((addr.s_addr = dot_quad_addr(host)) != INADDR_NONE) { 99 h.h_addr_list = addr_list; 100 h.h_addr_list[0] = (char *) &addr; 101 h.h_length = sizeof(addr); 102 return (dup_hostent(&h)); 103 } 104 105 /* 106 * Map host name to a series of addresses. Watch out for non-internet 107 * forms or aliases. The NOT_INADDR() is here in case gethostbyname() has 108 * been "enhanced" to accept numeric addresses. Make a copy of the 109 * address list so that later gethostbyXXX() calls will not clobber it. 110 */ 111 if (NOT_INADDR(host) == 0) { 112 tcpd_warn("%s: not an internet address", host); 113 return (0); 114 } 115 if ((hp = gethostbyname(host)) == 0) { 116 tcpd_warn("%s: host not found", host); 117 return (0); 118 } 119 if (hp->h_addrtype != AF_INET) { 120 tcpd_warn("%d: not an internet host", hp->h_addrtype); 121 return (0); 122 } 123 if (STR_NE(host, hp->h_name)) { 124 tcpd_warn("%s: hostname alias", host); 125 tcpd_warn("(official name: %s)", hp->h_name); 126 } 127 return (dup_hostent(hp)); 128 } 129 130 /* check_dns - give each address thorough workout, return address count */ 131 132 int check_dns(host) 133 char *host; 134 { 135 struct request_info request; 136 struct sockaddr_in sin; 137 struct hostent *hp; 138 int count; 139 char *addr; 140 141 if ((hp = find_inet_addr(host)) == 0) 142 return (0); 143 request_init(&request, RQ_CLIENT_SIN, &sin, 0); 144 sock_methods(&request); 145 memset((char *) &sin, 0, sizeof(sin)); 146 sin.sin_family = AF_INET; 147 148 for (count = 0; (addr = hp->h_addr_list[count]) != 0; count++) { 149 memcpy((char *) &sin.sin_addr, addr, sizeof(sin.sin_addr)); 150 151 /* 152 * Force host name and address conversions. Use the request structure 153 * as a cache. Detect hostname lookup problems. Any name/name or 154 * name/address conflicts will be reported while eval_hostname() does 155 * its job. 156 */ 157 request_set(&request, RQ_CLIENT_ADDR, "", RQ_CLIENT_NAME, "", 0); 158 if (STR_EQ(eval_hostname(request.client), unknown)) 159 tcpd_warn("host address %s->name lookup failed", 160 eval_hostaddr(request.client)); 161 } 162 free((char *) hp); 163 return (count); 164 } 165 166 /* dummy function to intercept the real shell_cmd() */ 167 168 /* ARGSUSED */ 169 170 void shell_cmd(command) 171 char *command; 172 { 173 if (hosts_access_verbose) 174 printf("command: %s", command); 175 } 176 177 /* dummy function to intercept the real clean_exit() */ 178 179 /* ARGSUSED */ 180 181 void clean_exit(request) 182 struct request_info *request; 183 { 184 exit(0); 185 } 186 187 #if 0 188 /* dummy function to intercept the real rfc931() */ 189 190 /* ARGSUSED */ 191 192 void rfc931(request) 193 struct request_info *request; 194 { 195 strcpy(request->user, unknown); 196 } 197 #endif 198 199 /* check_path - examine accessibility */ 200 201 int check_path(path, st) 202 char *path; 203 struct stat *st; 204 { 205 struct stat stbuf; 206 char buf[BUFSIZ]; 207 208 if (stat(path, st) < 0) 209 return (-1); 210 #ifdef notdef 211 if (st->st_uid != 0) 212 tcpd_warn("%s: not owned by root", path); 213 if (st->st_mode & 020) 214 tcpd_warn("%s: group writable", path); 215 #endif 216 if (st->st_mode & 002) 217 tcpd_warn("%s: world writable", path); 218 if (path[0] == '/' && path[1] != 0) { 219 strrchr(strcpy(buf, path), '/')[0] = 0; 220 (void) check_path(buf[0] ? buf : "/", &stbuf); 221 } 222 return (0); 223 } 224