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