144743Smarkm /* 244743Smarkm * Routines for testing only. Not really industrial strength. 344743Smarkm * 444743Smarkm * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands. 556977Sshin * 656977Sshin * $FreeBSD$ 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 3063158Sume#ifndef INET6 3144743Smarkmextern char *malloc(); 3263158Sume#endif 3344743Smarkm 3444743Smarkm/* Application-specific. */ 3544743Smarkm 3644743Smarkm#include "tcpd.h" 3744743Smarkm#include "scaffold.h" 3844743Smarkm 3944743Smarkm /* 4044743Smarkm * These are referenced by the options module and by rfc931.c. 4144743Smarkm */ 4244743Smarkmint allow_severity = SEVERITY; 4344743Smarkmint deny_severity = LOG_WARNING; 4444743Smarkmint rfc931_timeout = RFC931_TIMEOUT; 4544743Smarkm 4663158Sume#ifndef INET6 4744743Smarkm/* dup_hostent - create hostent in one memory block */ 4844743Smarkm 4944743Smarkmstatic struct hostent *dup_hostent(hp) 5044743Smarkmstruct hostent *hp; 5144743Smarkm{ 5244743Smarkm struct hostent_block { 5344743Smarkm struct hostent host; 5444743Smarkm char *addr_list[1]; 5544743Smarkm }; 5644743Smarkm struct hostent_block *hb; 5744743Smarkm int count; 5844743Smarkm char *data; 5944743Smarkm char *addr; 6044743Smarkm 6144743Smarkm for (count = 0; hp->h_addr_list[count] != 0; count++) 6244743Smarkm /* void */ ; 6344743Smarkm 6444743Smarkm if ((hb = (struct hostent_block *) malloc(sizeof(struct hostent_block) 6544743Smarkm + (hp->h_length + sizeof(char *)) * count)) == 0) { 6644743Smarkm fprintf(stderr, "Sorry, out of memory\n"); 6744743Smarkm exit(1); 6844743Smarkm } 6944743Smarkm memset((char *) &hb->host, 0, sizeof(hb->host)); 7044743Smarkm hb->host.h_length = hp->h_length; 7144743Smarkm hb->host.h_addr_list = hb->addr_list; 7244743Smarkm hb->host.h_addr_list[count] = 0; 7344743Smarkm data = (char *) (hb->host.h_addr_list + count + 1); 7444743Smarkm 7544743Smarkm for (count = 0; (addr = hp->h_addr_list[count]) != 0; count++) { 7644743Smarkm hb->host.h_addr_list[count] = data + hp->h_length * count; 7744743Smarkm memcpy(hb->host.h_addr_list[count], addr, hp->h_length); 7844743Smarkm } 7944743Smarkm return (&hb->host); 8044743Smarkm} 8163158Sume#endif 8244743Smarkm 8363158Sume/* find_inet_addr - find all addresses for this host, result to free() */ 8456977Sshin 8563158Sume#ifdef INET6 8663158Sumestruct addrinfo *find_inet_addr(host) 8763158Sumechar *host; 8856977Sshin{ 8963158Sume struct addrinfo hints, *res; 9056977Sshin 9163158Sume memset(&hints, 0, sizeof(hints)); 9263158Sume hints.ai_family = PF_UNSPEC; 9363158Sume hints.ai_socktype = SOCK_STREAM; 9463158Sume hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; 9563158Sume if (getaddrinfo(host, NULL, &hints, &res) == 0) 9663158Sume return (res); 9756977Sshin 9863158Sume memset(&hints, 0, sizeof(hints)); 9963158Sume hints.ai_family = PF_UNSPEC; 10063158Sume hints.ai_socktype = SOCK_STREAM; 10163158Sume hints.ai_flags = AI_PASSIVE | AI_CANONNAME; 10263158Sume if (getaddrinfo(host, NULL, &hints, &res) != 0) { 10363158Sume tcpd_warn("%s: host not found", host); 10463158Sume return (0); 10556977Sshin } 10663158Sume if (res->ai_family != AF_INET6 && res->ai_family != AF_INET) { 10763158Sume tcpd_warn("%d: not an internet host", res->ai_family); 10863158Sume freeaddrinfo(res); 10963158Sume return (0); 11056977Sshin } 11163158Sume if (!res->ai_canonname) { 11263158Sume tcpd_warn("%s: hostname alias", host); 11363158Sume tcpd_warn("(cannot obtain official name)", res->ai_canonname); 11463158Sume } else if (STR_NE(host, res->ai_canonname)) { 11563158Sume tcpd_warn("%s: hostname alias", host); 11663158Sume tcpd_warn("(official name: %.*s)", STRING_LENGTH, res->ai_canonname); 11756977Sshin } 11863158Sume return (res); 11956977Sshin} 12056977Sshin#else 12144743Smarkmstruct hostent *find_inet_addr(host) 12244743Smarkmchar *host; 12344743Smarkm{ 12444743Smarkm struct in_addr addr; 12544743Smarkm struct hostent *hp; 12644743Smarkm static struct hostent h; 12744743Smarkm static char *addr_list[2]; 12844743Smarkm 12944743Smarkm /* 13044743Smarkm * Host address: translate it to internal form. 13144743Smarkm */ 13244743Smarkm if ((addr.s_addr = dot_quad_addr(host)) != INADDR_NONE) { 13344743Smarkm h.h_addr_list = addr_list; 13444743Smarkm h.h_addr_list[0] = (char *) &addr; 13544743Smarkm h.h_length = sizeof(addr); 13644743Smarkm return (dup_hostent(&h)); 13744743Smarkm } 13844743Smarkm 13944743Smarkm /* 14044743Smarkm * Map host name to a series of addresses. Watch out for non-internet 14144743Smarkm * forms or aliases. The NOT_INADDR() is here in case gethostbyname() has 14244743Smarkm * been "enhanced" to accept numeric addresses. Make a copy of the 14344743Smarkm * address list so that later gethostbyXXX() calls will not clobber it. 14444743Smarkm */ 14544743Smarkm if (NOT_INADDR(host) == 0) { 14644743Smarkm tcpd_warn("%s: not an internet address", host); 14744743Smarkm return (0); 14844743Smarkm } 14944743Smarkm if ((hp = gethostbyname(host)) == 0) { 15044743Smarkm tcpd_warn("%s: host not found", host); 15144743Smarkm return (0); 15244743Smarkm } 15344743Smarkm if (hp->h_addrtype != AF_INET) { 15444743Smarkm tcpd_warn("%d: not an internet host", hp->h_addrtype); 15544743Smarkm return (0); 15644743Smarkm } 15744743Smarkm if (STR_NE(host, hp->h_name)) { 15844743Smarkm tcpd_warn("%s: hostname alias", host); 15944743Smarkm tcpd_warn("(official name: %.*s)", STRING_LENGTH, hp->h_name); 16044743Smarkm } 16144743Smarkm return (dup_hostent(hp)); 16263158Sume} 16356977Sshin#endif 16444743Smarkm 16544743Smarkm/* check_dns - give each address thorough workout, return address count */ 16644743Smarkm 16744743Smarkmint check_dns(host) 16844743Smarkmchar *host; 16944743Smarkm{ 17044743Smarkm struct request_info request; 17156977Sshin#ifdef INET6 17256977Sshin struct sockaddr_storage sin; 17363158Sume struct addrinfo *hp, *res; 17456977Sshin#else 17544743Smarkm struct sockaddr_in sin; 17663158Sume struct hostent *hp; 17756977Sshin#endif 17844743Smarkm int count; 17944743Smarkm char *addr; 18044743Smarkm 18144743Smarkm if ((hp = find_inet_addr(host)) == 0) 18244743Smarkm return (0); 18344743Smarkm request_init(&request, RQ_CLIENT_SIN, &sin, 0); 18444743Smarkm sock_methods(&request); 18563158Sume#ifndef INET6 18644743Smarkm memset((char *) &sin, 0, sizeof(sin)); 18744743Smarkm sin.sin_family = AF_INET; 18856977Sshin#endif 18944743Smarkm 19056977Sshin#ifdef INET6 19163158Sume for (res = hp, count = 0; res; res = res->ai_next, count++) { 19263158Sume memcpy(&sin, res->ai_addr, res->ai_addrlen); 19356977Sshin#else 19463158Sume for (count = 0; (addr = hp->h_addr_list[count]) != 0; count++) { 19544743Smarkm memcpy((char *) &sin.sin_addr, addr, sizeof(sin.sin_addr)); 19656977Sshin#endif 19744743Smarkm 19844743Smarkm /* 19944743Smarkm * Force host name and address conversions. Use the request structure 20044743Smarkm * as a cache. Detect hostname lookup problems. Any name/name or 20144743Smarkm * name/address conflicts will be reported while eval_hostname() does 20244743Smarkm * its job. 20344743Smarkm */ 20444743Smarkm request_set(&request, RQ_CLIENT_ADDR, "", RQ_CLIENT_NAME, "", 0); 20544743Smarkm if (STR_EQ(eval_hostname(request.client), unknown)) 20644743Smarkm tcpd_warn("host address %s->name lookup failed", 20744743Smarkm eval_hostaddr(request.client)); 20844743Smarkm } 20963158Sume#ifdef INET6 21063158Sume freeaddrinfo(hp); 21163158Sume#else 21244743Smarkm free((char *) hp); 21363158Sume#endif 21444743Smarkm return (count); 21544743Smarkm} 21644743Smarkm 21744743Smarkm/* dummy function to intercept the real shell_cmd() */ 21844743Smarkm 21944743Smarkm/* ARGSUSED */ 22044743Smarkm 22144743Smarkmvoid shell_cmd(command) 22244743Smarkmchar *command; 22344743Smarkm{ 22444743Smarkm if (hosts_access_verbose) 22544743Smarkm printf("command: %s", command); 22644743Smarkm} 22744743Smarkm 22844743Smarkm/* dummy function to intercept the real clean_exit() */ 22944743Smarkm 23044743Smarkm/* ARGSUSED */ 23144743Smarkm 23244743Smarkmvoid clean_exit(request) 23344743Smarkmstruct request_info *request; 23444743Smarkm{ 23544743Smarkm exit(0); 23644743Smarkm} 23744743Smarkm 23844743Smarkm/* dummy function to intercept the real rfc931() */ 23944743Smarkm 24044743Smarkm/* ARGSUSED */ 24144743Smarkm 24244743Smarkmvoid rfc931(request) 24344743Smarkmstruct request_info *request; 24444743Smarkm{ 24544743Smarkm strcpy(request->user, unknown); 24644743Smarkm} 24744743Smarkm 24844743Smarkm/* check_path - examine accessibility */ 24944743Smarkm 25044743Smarkmint check_path(path, st) 25144743Smarkmchar *path; 25244743Smarkmstruct stat *st; 25344743Smarkm{ 25444743Smarkm struct stat stbuf; 25544743Smarkm char buf[BUFSIZ]; 25644743Smarkm 25744743Smarkm if (stat(path, st) < 0) 25844743Smarkm return (-1); 25944743Smarkm#ifdef notdef 26044743Smarkm if (st->st_uid != 0) 26144743Smarkm tcpd_warn("%s: not owned by root", path); 26244743Smarkm if (st->st_mode & 020) 26344743Smarkm tcpd_warn("%s: group writable", path); 26444743Smarkm#endif 26544743Smarkm if (st->st_mode & 002) 26644743Smarkm tcpd_warn("%s: world writable", path); 26744743Smarkm if (path[0] == '/' && path[1] != 0) { 26844743Smarkm strrchr(strcpy(buf, path), '/')[0] = 0; 26944743Smarkm (void) check_path(buf[0] ? buf : "/", &stbuf); 27044743Smarkm } 27144743Smarkm return (0); 27244743Smarkm} 273