1 /* $NetBSD: scaffold.c,v 1.7 1999/08/31 13:58:58 itojun 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.6 97/03/21 19:27:24"; 13 #else 14 __RCSID("$NetBSD: scaffold.c,v 1.7 1999/08/31 13:58:58 itojun 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_addrtype = hp->h_addrtype; 74 hb->host.h_length = hp->h_length; 75 hb->host.h_addr_list = hb->addr_list; 76 hb->host.h_addr_list[count] = 0; 77 data = (char *) (hb->host.h_addr_list + count + 1); 78 79 for (count = 0; (addr = hp->h_addr_list[count]) != 0; count++) { 80 hb->host.h_addr_list[count] = data + hp->h_length * count; 81 memcpy(hb->host.h_addr_list[count], addr, hp->h_length); 82 } 83 return (&hb->host); 84 } 85 86 /* find_inet_addr - find all addresses for this host, result to free() */ 87 88 struct hostent *find_inet_addr(host) 89 char *host; 90 { 91 struct in_addr addr; 92 unsigned long addr_num; 93 struct hostent *hp; 94 static struct hostent h; 95 static char *addr_list[2]; 96 #ifdef INET6 97 static struct in6_addr in6; 98 #endif 99 100 /* 101 * Host address: translate it to internal form. 102 */ 103 if (dot_quad_addr(host, &addr_num) == 0) { 104 addr.s_addr = (addr_num & 0xffffffff); 105 h.h_addr_list = addr_list; 106 h.h_addr_list[0] = (char *) &addr; 107 h.h_length = sizeof(addr); 108 h.h_addrtype = AF_INET; 109 return (dup_hostent(&h)); 110 } 111 #ifdef INET6 112 if (inet_pton(AF_INET6, host, &in6) == 1) { 113 h.h_addr_list = addr_list; 114 h.h_addr_list[0] = (char *) &in6; 115 h.h_length = sizeof(in6); 116 h.h_addrtype = AF_INET6; 117 return (dup_hostent(&h)); 118 } 119 #endif 120 121 /* 122 * Map host name to a series of addresses. Watch out for non-internet 123 * forms or aliases. The NOT_INADDR() is here in case gethostbyname() has 124 * been "enhanced" to accept numeric addresses. Make a copy of the 125 * address list so that later gethostbyXXX() calls will not clobber it. 126 */ 127 #ifdef INET6 128 if (NOT_INADDR(host) == 0 && inet_pton(AF_INET6, host, &in6) == 1) 129 #else 130 if (NOT_INADDR(host) == 0) 131 #endif 132 { 133 tcpd_warn("%s: not an internet address", host); 134 return (0); 135 } 136 #ifdef INET6 137 /* 138 * XXX this behavior may, or may not be desirable. 139 * - we may better use getipnodebyname() to addresses of get both AFs, 140 * however, getipnodebyname() is not widely implemented. 141 * - it may be better to have a way to specify the AF to use. 142 */ 143 if ((hp = gethostbyname2(host, AF_INET)) == 0 144 && (hp = gethostbyname2(host, AF_INET6)) == 0) { 145 tcpd_warn("%s: host not found", host); 146 return (0); 147 } 148 #else 149 if ((hp = gethostbyname(host)) == 0) { 150 tcpd_warn("%s: host not found", host); 151 return (0); 152 } 153 if (hp->h_addrtype != AF_INET) { 154 tcpd_warn("%d: not an internet host", hp->h_addrtype); 155 return (0); 156 } 157 #endif 158 if (STR_NE(host, hp->h_name)) { 159 tcpd_warn("%s: hostname alias", host); 160 tcpd_warn("(official name: %.*s)", STRING_LENGTH, hp->h_name); 161 } 162 return (dup_hostent(hp)); 163 } 164 165 /* check_dns - give each address thorough workout, return address count */ 166 167 int check_dns(host) 168 char *host; 169 { 170 struct request_info request; 171 struct sockaddr_storage sin; 172 struct hostent *hp; 173 int count; 174 char *addr; 175 char *ap; 176 int alen; 177 178 if ((hp = find_inet_addr(host)) == 0) 179 return (0); 180 request_init(&request, RQ_CLIENT_SIN, &sin, 0); 181 sock_methods(&request); 182 memset((char *) &sin, 0, sizeof(sin)); 183 sin.ss_family = hp->h_addrtype; 184 switch (hp->h_addrtype) { 185 case AF_INET: 186 ap = (char *)&((struct sockaddr_in *)&sin)->sin_addr; 187 alen = sizeof(struct in6_addr); 188 break; 189 #ifdef INET6 190 case AF_INET6: 191 ap = (char *)&((struct sockaddr_in6 *)&sin)->sin6_addr; 192 alen = sizeof(struct in6_addr); 193 break; 194 #endif 195 default: 196 return (0); 197 } 198 199 for (count = 0; (addr = hp->h_addr_list[count]) != 0; count++) { 200 memcpy(ap, addr, alen); 201 202 /* 203 * Force host name and address conversions. Use the request structure 204 * as a cache. Detect hostname lookup problems. Any name/name or 205 * name/address conflicts will be reported while eval_hostname() does 206 * its job. 207 */ 208 request_set(&request, RQ_CLIENT_ADDR, "", RQ_CLIENT_NAME, "", 0); 209 if (STR_EQ(eval_hostname(request.client), unknown)) 210 tcpd_warn("host address %s->name lookup failed", 211 eval_hostaddr(request.client)); 212 } 213 free((char *) hp); 214 return (count); 215 } 216 217 /* dummy function to intercept the real shell_cmd() */ 218 219 /* ARGSUSED */ 220 221 void shell_cmd(command) 222 char *command; 223 { 224 if (hosts_access_verbose) 225 printf("command: %s", command); 226 } 227 228 /* dummy function to intercept the real clean_exit() */ 229 230 /* ARGSUSED */ 231 232 void clean_exit(request) 233 struct request_info *request; 234 { 235 exit(0); 236 } 237 238 #if 0 239 /* dummy function to intercept the real rfc931() */ 240 241 /* ARGSUSED */ 242 243 void rfc931(request) 244 struct request_info *request; 245 { 246 strcpy(request->user, unknown); 247 } 248 #endif 249 250 /* check_path - examine accessibility */ 251 252 int check_path(path, st) 253 char *path; 254 struct stat *st; 255 { 256 struct stat stbuf; 257 char buf[BUFSIZ]; 258 259 if (stat(path, st) < 0) 260 return (-1); 261 #ifdef notdef 262 if (st->st_uid != 0) 263 tcpd_warn("%s: not owned by root", path); 264 if (st->st_mode & 020) 265 tcpd_warn("%s: group writable", path); 266 #endif 267 if (st->st_mode & 002) 268 tcpd_warn("%s: world writable", path); 269 if (path[0] == '/' && path[1] != 0) { 270 strrchr(strcpy(buf, path), '/')[0] = 0; 271 (void) check_path(buf[0] ? buf : "/", &stbuf); 272 } 273 return (0); 274 } 275