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