144743Smarkm /* 244743Smarkm * Routines for testing only. Not really industrial strength. 344743Smarkm * 444743Smarkm * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands. 556977Sshin * 656977Sshin * $FreeBSD: stable/10/contrib/tcp_wrappers/scaffold.c 323744 2017-09-19 08:34:13Z avg $ 744743Smarkm */ 844743Smarkm 944743Smarkm#ifndef lint 1044743Smarkmstatic char sccs_id[] = "@(#) scaffold.c 1.6 97/03/21 19:27:24"; 1144743Smarkm#endif 1244743Smarkm 1344743Smarkm/* System libraries. */ 1444743Smarkm 1544743Smarkm#include <sys/types.h> 1644743Smarkm#include <sys/stat.h> 1744743Smarkm#include <sys/socket.h> 1844743Smarkm#include <netinet/in.h> 1944743Smarkm#include <arpa/inet.h> 2044743Smarkm#include <netdb.h> 2144743Smarkm#include <stdio.h> 2244743Smarkm#include <syslog.h> 2344743Smarkm#include <setjmp.h> 2444743Smarkm#include <string.h> 2544743Smarkm 2644743Smarkm#ifndef INADDR_NONE 2744743Smarkm#define INADDR_NONE (-1) /* XXX should be 0xffffffff */ 2844743Smarkm#endif 2944743Smarkm 3044743Smarkm/* Application-specific. */ 3144743Smarkm 3244743Smarkm#include "tcpd.h" 3344743Smarkm#include "scaffold.h" 3444743Smarkm 3544743Smarkm /* 3644743Smarkm * These are referenced by the options module and by rfc931.c. 3744743Smarkm */ 3844743Smarkmint allow_severity = SEVERITY; 3944743Smarkmint deny_severity = LOG_WARNING; 4044743Smarkmint rfc931_timeout = RFC931_TIMEOUT; 4144743Smarkm 4263158Sume#ifndef INET6 4344743Smarkm/* dup_hostent - create hostent in one memory block */ 4444743Smarkm 4544743Smarkmstatic struct hostent *dup_hostent(hp) 4644743Smarkmstruct hostent *hp; 4744743Smarkm{ 4844743Smarkm struct hostent_block { 4944743Smarkm struct hostent host; 5044743Smarkm char *addr_list[1]; 5144743Smarkm }; 5244743Smarkm struct hostent_block *hb; 5344743Smarkm int count; 5444743Smarkm char *data; 5544743Smarkm char *addr; 5644743Smarkm 5744743Smarkm for (count = 0; hp->h_addr_list[count] != 0; count++) 5844743Smarkm /* void */ ; 5944743Smarkm 6044743Smarkm if ((hb = (struct hostent_block *) malloc(sizeof(struct hostent_block) 6144743Smarkm + (hp->h_length + sizeof(char *)) * count)) == 0) { 6244743Smarkm fprintf(stderr, "Sorry, out of memory\n"); 6344743Smarkm exit(1); 6444743Smarkm } 6544743Smarkm memset((char *) &hb->host, 0, sizeof(hb->host)); 6644743Smarkm hb->host.h_length = hp->h_length; 6744743Smarkm hb->host.h_addr_list = hb->addr_list; 6844743Smarkm hb->host.h_addr_list[count] = 0; 6944743Smarkm data = (char *) (hb->host.h_addr_list + count + 1); 7044743Smarkm 7144743Smarkm for (count = 0; (addr = hp->h_addr_list[count]) != 0; count++) { 7244743Smarkm hb->host.h_addr_list[count] = data + hp->h_length * count; 7344743Smarkm memcpy(hb->host.h_addr_list[count], addr, hp->h_length); 7444743Smarkm } 7544743Smarkm return (&hb->host); 7644743Smarkm} 7763158Sume#endif 7844743Smarkm 7963158Sume/* find_inet_addr - find all addresses for this host, result to free() */ 8056977Sshin 8163158Sume#ifdef INET6 8263158Sumestruct addrinfo *find_inet_addr(host) 8363158Sumechar *host; 8456977Sshin{ 8563158Sume struct addrinfo hints, *res; 8656977Sshin 8763158Sume memset(&hints, 0, sizeof(hints)); 8863158Sume hints.ai_family = PF_UNSPEC; 8963158Sume hints.ai_socktype = SOCK_STREAM; 9063158Sume hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; 9163158Sume if (getaddrinfo(host, NULL, &hints, &res) == 0) 9263158Sume return (res); 9356977Sshin 9463158Sume memset(&hints, 0, sizeof(hints)); 9563158Sume hints.ai_family = PF_UNSPEC; 9663158Sume hints.ai_socktype = SOCK_STREAM; 9763158Sume hints.ai_flags = AI_PASSIVE | AI_CANONNAME; 9863158Sume if (getaddrinfo(host, NULL, &hints, &res) != 0) { 9963158Sume tcpd_warn("%s: host not found", host); 10063158Sume return (0); 10156977Sshin } 10263158Sume if (res->ai_family != AF_INET6 && res->ai_family != AF_INET) { 10363158Sume tcpd_warn("%d: not an internet host", res->ai_family); 10463158Sume freeaddrinfo(res); 10563158Sume return (0); 10656977Sshin } 10763158Sume if (!res->ai_canonname) { 10863158Sume tcpd_warn("%s: hostname alias", host); 10963158Sume tcpd_warn("(cannot obtain official name)", res->ai_canonname); 11063158Sume } else if (STR_NE(host, res->ai_canonname)) { 11163158Sume tcpd_warn("%s: hostname alias", host); 11263158Sume tcpd_warn("(official name: %.*s)", STRING_LENGTH, res->ai_canonname); 11356977Sshin } 11463158Sume return (res); 11556977Sshin} 11656977Sshin#else 11744743Smarkmstruct hostent *find_inet_addr(host) 11844743Smarkmchar *host; 11944743Smarkm{ 12044743Smarkm struct in_addr addr; 12144743Smarkm struct hostent *hp; 12244743Smarkm static struct hostent h; 12344743Smarkm static char *addr_list[2]; 12444743Smarkm 12544743Smarkm /* 12644743Smarkm * Host address: translate it to internal form. 12744743Smarkm */ 12844743Smarkm if ((addr.s_addr = dot_quad_addr(host)) != INADDR_NONE) { 12944743Smarkm h.h_addr_list = addr_list; 13044743Smarkm h.h_addr_list[0] = (char *) &addr; 13144743Smarkm h.h_length = sizeof(addr); 13244743Smarkm return (dup_hostent(&h)); 13344743Smarkm } 13444743Smarkm 13544743Smarkm /* 13644743Smarkm * Map host name to a series of addresses. Watch out for non-internet 13744743Smarkm * forms or aliases. The NOT_INADDR() is here in case gethostbyname() has 13844743Smarkm * been "enhanced" to accept numeric addresses. Make a copy of the 13944743Smarkm * address list so that later gethostbyXXX() calls will not clobber it. 14044743Smarkm */ 14144743Smarkm if (NOT_INADDR(host) == 0) { 14244743Smarkm tcpd_warn("%s: not an internet address", host); 14344743Smarkm return (0); 14444743Smarkm } 14544743Smarkm if ((hp = gethostbyname(host)) == 0) { 14644743Smarkm tcpd_warn("%s: host not found", host); 14744743Smarkm return (0); 14844743Smarkm } 14944743Smarkm if (hp->h_addrtype != AF_INET) { 15044743Smarkm tcpd_warn("%d: not an internet host", hp->h_addrtype); 15144743Smarkm return (0); 15244743Smarkm } 15344743Smarkm if (STR_NE(host, hp->h_name)) { 15444743Smarkm tcpd_warn("%s: hostname alias", host); 15544743Smarkm tcpd_warn("(official name: %.*s)", STRING_LENGTH, hp->h_name); 15644743Smarkm } 15744743Smarkm return (dup_hostent(hp)); 15863158Sume} 15956977Sshin#endif 16044743Smarkm 16144743Smarkm/* check_dns - give each address thorough workout, return address count */ 16244743Smarkm 16344743Smarkmint check_dns(host) 16444743Smarkmchar *host; 16544743Smarkm{ 16644743Smarkm struct request_info request; 16756977Sshin#ifdef INET6 16856977Sshin struct sockaddr_storage sin; 16963158Sume struct addrinfo *hp, *res; 17056977Sshin#else 17144743Smarkm struct sockaddr_in sin; 17263158Sume struct hostent *hp; 17356977Sshin#endif 17444743Smarkm int count; 17544743Smarkm char *addr; 17644743Smarkm 17744743Smarkm if ((hp = find_inet_addr(host)) == 0) 17844743Smarkm return (0); 17944743Smarkm request_init(&request, RQ_CLIENT_SIN, &sin, 0); 18044743Smarkm sock_methods(&request); 18163158Sume#ifndef INET6 18244743Smarkm memset((char *) &sin, 0, sizeof(sin)); 18344743Smarkm sin.sin_family = AF_INET; 18456977Sshin#endif 18544743Smarkm 18656977Sshin#ifdef INET6 18763158Sume for (res = hp, count = 0; res; res = res->ai_next, count++) { 18863158Sume memcpy(&sin, res->ai_addr, res->ai_addrlen); 18956977Sshin#else 19063158Sume for (count = 0; (addr = hp->h_addr_list[count]) != 0; count++) { 19144743Smarkm memcpy((char *) &sin.sin_addr, addr, sizeof(sin.sin_addr)); 19256977Sshin#endif 19344743Smarkm 19444743Smarkm /* 19544743Smarkm * Force host name and address conversions. Use the request structure 19644743Smarkm * as a cache. Detect hostname lookup problems. Any name/name or 19744743Smarkm * name/address conflicts will be reported while eval_hostname() does 19844743Smarkm * its job. 19944743Smarkm */ 20044743Smarkm request_set(&request, RQ_CLIENT_ADDR, "", RQ_CLIENT_NAME, "", 0); 20144743Smarkm if (STR_EQ(eval_hostname(request.client), unknown)) 20244743Smarkm tcpd_warn("host address %s->name lookup failed", 20344743Smarkm eval_hostaddr(request.client)); 20444743Smarkm } 20563158Sume#ifdef INET6 20663158Sume freeaddrinfo(hp); 20763158Sume#else 20844743Smarkm free((char *) hp); 20963158Sume#endif 21044743Smarkm return (count); 21144743Smarkm} 21244743Smarkm 21344743Smarkm/* dummy function to intercept the real shell_cmd() */ 21444743Smarkm 21544743Smarkm/* ARGSUSED */ 21644743Smarkm 21744743Smarkmvoid shell_cmd(command) 21844743Smarkmchar *command; 21944743Smarkm{ 22044743Smarkm if (hosts_access_verbose) 22144743Smarkm printf("command: %s", command); 22244743Smarkm} 22344743Smarkm 22444743Smarkm/* dummy function to intercept the real clean_exit() */ 22544743Smarkm 22644743Smarkm/* ARGSUSED */ 22744743Smarkm 22844743Smarkmvoid clean_exit(request) 22944743Smarkmstruct request_info *request; 23044743Smarkm{ 23144743Smarkm exit(0); 23244743Smarkm} 23344743Smarkm 23444743Smarkm/* check_path - examine accessibility */ 23544743Smarkm 23644743Smarkmint check_path(path, st) 23744743Smarkmchar *path; 23844743Smarkmstruct stat *st; 23944743Smarkm{ 24044743Smarkm struct stat stbuf; 24144743Smarkm char buf[BUFSIZ]; 24244743Smarkm 24344743Smarkm if (stat(path, st) < 0) 24444743Smarkm return (-1); 24544743Smarkm#ifdef notdef 24644743Smarkm if (st->st_uid != 0) 24744743Smarkm tcpd_warn("%s: not owned by root", path); 24844743Smarkm if (st->st_mode & 020) 24944743Smarkm tcpd_warn("%s: group writable", path); 25044743Smarkm#endif 25144743Smarkm if (st->st_mode & 002) 25244743Smarkm tcpd_warn("%s: world writable", path); 25344743Smarkm if (path[0] == '/' && path[1] != 0) { 25444743Smarkm strrchr(strcpy(buf, path), '/')[0] = 0; 25544743Smarkm (void) check_path(buf[0] ? buf : "/", &stbuf); 25644743Smarkm } 25744743Smarkm return (0); 25844743Smarkm} 259