1 /* 2 * Routines for testing only. Not really industrial strength. 3 * 4 * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands. 5 * 6 * $FreeBSD$ 7 */ 8 9 #ifndef lint 10 static char sccs_id[] = "@(#) scaffold.c 1.6 97/03/21 19:27:24"; 11 #endif 12 13 /* System libraries. */ 14 15 #include <sys/types.h> 16 #include <sys/stat.h> 17 #include <sys/socket.h> 18 #include <netinet/in.h> 19 #include <arpa/inet.h> 20 #include <netdb.h> 21 #include <stdio.h> 22 #include <syslog.h> 23 #include <setjmp.h> 24 #include <string.h> 25 26 #ifndef INADDR_NONE 27 #define INADDR_NONE (-1) /* XXX should be 0xffffffff */ 28 #endif 29 30 #ifndef INET6 31 extern char *malloc(); 32 #endif 33 34 /* Application-specific. */ 35 36 #include "tcpd.h" 37 #include "scaffold.h" 38 39 /* 40 * These are referenced by the options module and by rfc931.c. 41 */ 42 int allow_severity = SEVERITY; 43 int deny_severity = LOG_WARNING; 44 int rfc931_timeout = RFC931_TIMEOUT; 45 46 #ifndef INET6 47 /* dup_hostent - create hostent in one memory block */ 48 49 static struct hostent *dup_hostent(hp) 50 struct hostent *hp; 51 { 52 struct hostent_block { 53 struct hostent host; 54 char *addr_list[1]; 55 }; 56 struct hostent_block *hb; 57 int count; 58 char *data; 59 char *addr; 60 61 for (count = 0; hp->h_addr_list[count] != 0; count++) 62 /* void */ ; 63 64 if ((hb = (struct hostent_block *) malloc(sizeof(struct hostent_block) 65 + (hp->h_length + sizeof(char *)) * count)) == 0) { 66 fprintf(stderr, "Sorry, out of memory\n"); 67 exit(1); 68 } 69 memset((char *) &hb->host, 0, sizeof(hb->host)); 70 hb->host.h_length = hp->h_length; 71 hb->host.h_addr_list = hb->addr_list; 72 hb->host.h_addr_list[count] = 0; 73 data = (char *) (hb->host.h_addr_list + count + 1); 74 75 for (count = 0; (addr = hp->h_addr_list[count]) != 0; count++) { 76 hb->host.h_addr_list[count] = data + hp->h_length * count; 77 memcpy(hb->host.h_addr_list[count], addr, hp->h_length); 78 } 79 return (&hb->host); 80 } 81 #endif 82 83 /* find_inet_addr - find all addresses for this host, result to free() */ 84 85 #ifdef INET6 86 struct addrinfo *find_inet_addr(host) 87 char *host; 88 { 89 struct addrinfo hints, *res; 90 91 memset(&hints, 0, sizeof(hints)); 92 hints.ai_family = PF_UNSPEC; 93 hints.ai_socktype = SOCK_STREAM; 94 hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; 95 if (getaddrinfo(host, NULL, &hints, &res) == 0) 96 return (res); 97 98 memset(&hints, 0, sizeof(hints)); 99 hints.ai_family = PF_UNSPEC; 100 hints.ai_socktype = SOCK_STREAM; 101 hints.ai_flags = AI_PASSIVE | AI_CANONNAME; 102 if (getaddrinfo(host, NULL, &hints, &res) != 0) { 103 tcpd_warn("%s: host not found", host); 104 return (0); 105 } 106 if (res->ai_family != AF_INET6 && res->ai_family != AF_INET) { 107 tcpd_warn("%d: not an internet host", res->ai_family); 108 freeaddrinfo(res); 109 return (0); 110 } 111 if (!res->ai_canonname) { 112 tcpd_warn("%s: hostname alias", host); 113 tcpd_warn("(cannot obtain official name)", res->ai_canonname); 114 } else if (STR_NE(host, res->ai_canonname)) { 115 tcpd_warn("%s: hostname alias", host); 116 tcpd_warn("(official name: %.*s)", STRING_LENGTH, res->ai_canonname); 117 } 118 return (res); 119 } 120 #else 121 struct hostent *find_inet_addr(host) 122 char *host; 123 { 124 struct in_addr addr; 125 struct hostent *hp; 126 static struct hostent h; 127 static char *addr_list[2]; 128 129 /* 130 * Host address: translate it to internal form. 131 */ 132 if ((addr.s_addr = dot_quad_addr(host)) != INADDR_NONE) { 133 h.h_addr_list = addr_list; 134 h.h_addr_list[0] = (char *) &addr; 135 h.h_length = sizeof(addr); 136 return (dup_hostent(&h)); 137 } 138 139 /* 140 * Map host name to a series of addresses. Watch out for non-internet 141 * forms or aliases. The NOT_INADDR() is here in case gethostbyname() has 142 * been "enhanced" to accept numeric addresses. Make a copy of the 143 * address list so that later gethostbyXXX() calls will not clobber it. 144 */ 145 if (NOT_INADDR(host) == 0) { 146 tcpd_warn("%s: not an internet address", host); 147 return (0); 148 } 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 if (STR_NE(host, hp->h_name)) { 158 tcpd_warn("%s: hostname alias", host); 159 tcpd_warn("(official name: %.*s)", STRING_LENGTH, hp->h_name); 160 } 161 return (dup_hostent(hp)); 162 } 163 #endif 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 #ifdef INET6 172 struct sockaddr_storage sin; 173 struct addrinfo *hp, *res; 174 #else 175 struct sockaddr_in sin; 176 struct hostent *hp; 177 #endif 178 int count; 179 char *addr; 180 181 if ((hp = find_inet_addr(host)) == 0) 182 return (0); 183 request_init(&request, RQ_CLIENT_SIN, &sin, 0); 184 sock_methods(&request); 185 #ifndef INET6 186 memset((char *) &sin, 0, sizeof(sin)); 187 sin.sin_family = AF_INET; 188 #endif 189 190 #ifdef INET6 191 for (res = hp, count = 0; res; res = res->ai_next, count++) { 192 memcpy(&sin, res->ai_addr, res->ai_addrlen); 193 #else 194 for (count = 0; (addr = hp->h_addr_list[count]) != 0; count++) { 195 memcpy((char *) &sin.sin_addr, addr, sizeof(sin.sin_addr)); 196 #endif 197 198 /* 199 * Force host name and address conversions. Use the request structure 200 * as a cache. Detect hostname lookup problems. Any name/name or 201 * name/address conflicts will be reported while eval_hostname() does 202 * its job. 203 */ 204 request_set(&request, RQ_CLIENT_ADDR, "", RQ_CLIENT_NAME, "", 0); 205 if (STR_EQ(eval_hostname(request.client), unknown)) 206 tcpd_warn("host address %s->name lookup failed", 207 eval_hostaddr(request.client)); 208 } 209 #ifdef INET6 210 freeaddrinfo(hp); 211 #else 212 free((char *) hp); 213 #endif 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 /* dummy function to intercept the real rfc931() */ 239 240 /* ARGSUSED */ 241 242 void rfc931(request) 243 struct request_info *request; 244 { 245 strcpy(request->user, unknown); 246 } 247 248 /* check_path - examine accessibility */ 249 250 int check_path(path, st) 251 char *path; 252 struct stat *st; 253 { 254 struct stat stbuf; 255 char buf[BUFSIZ]; 256 257 if (stat(path, st) < 0) 258 return (-1); 259 #ifdef notdef 260 if (st->st_uid != 0) 261 tcpd_warn("%s: not owned by root", path); 262 if (st->st_mode & 020) 263 tcpd_warn("%s: group writable", path); 264 #endif 265 if (st->st_mode & 002) 266 tcpd_warn("%s: world writable", path); 267 if (path[0] == '/' && path[1] != 0) { 268 strrchr(strcpy(buf, path), '/')[0] = 0; 269 (void) check_path(buf[0] ? buf : "/", &stbuf); 270 } 271 return (0); 272 } 273